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

#include "HTTPConnection.h"

#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>

#include "url/URI.h"
#include "http/HTTPUtil.h"

#include "Test.util.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

using namespace http;

void HttpConnection::sendRequest()
{
    std::ostream stream(&request);
    stream << current->getRequestMessage().toString();
    stream << "\r\n";
    boost::asio::async_write(socket, request, boost::bind(&HttpConnection::handleWriteRequest, this, boost::asio::placeholders::error));
}

void HttpConnection::done(bool error)
{
    line.clear();
    if (current) {
        current->notify(error);
        current = 0;
    }
    if (!error) {
        if (!requests.empty()) {
            current = requests.front();
            requests.pop_front();
            sendRequest();
        }
    } else {
        while (!requests.empty()) {
            current = requests.front();
            requests.pop_front();
            current->notify(error);
        }
        current = 0;
    }
}

void HttpConnection::close()
{
    state = Closed;
    line.clear();
    retryCount = 0;
    response.consume(response.size());
    socket.close();
}

void HttpConnection::retry()
{
    close();
    ++retryCount;
    if (retryCount < MaxRetryCount)
        send(current);
    else
        done(true);
}

void HttpConnection::handleResolve(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpointIterator)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << err << '\n';

    if (!err) {
        state = Resolved;
        boost::asio::ip::tcp::endpoint endpoint = *endpointIterator;
        socket.async_connect(endpoint, boost::bind(&HttpConnection::handleConnect, this, boost::asio::placeholders::error, ++endpointIterator));
        return;
    }
    done(true);
}

void HttpConnection::handleConnect(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpointIterator)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << err << '\n';

    if (!err) {
        state = Connected;
        if (current) {
            sendRequest();
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
        }
        return;
    }
    if (endpointIterator != boost::asio::ip::tcp::resolver::iterator()) {
        close();
        boost::asio::ip::tcp::endpoint endpoint = *endpointIterator;
        socket.async_connect(endpoint, boost::bind(&HttpConnection::handleConnect, this, boost::asio::placeholders::error, ++endpointIterator));
        return;
    }
    done(true);
}

void HttpConnection::handleRead(const boost::system::error_code& err)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << state << ' ' << err << '\n';

    switch (state) {
    case Closed:
        break;
    case ReadStatusLine:
        readStatusLine(err);
        break;
    case ReadHead:
        readHead(err);
        break;
    case ReadContent:
        readContent(err);
        break;
    case ReadChunk:
        readChunk(err);
        break;
    case ReadTrailer:
        readTrailer(err);
        break;
    case CloseWait:
        close();
        break;
    default:
        close();
        done(true);
        break;
    }
}

void HttpConnection::handleWriteRequest(const boost::system::error_code& err)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << err <<  '\n';

    if (!err && current) {
        if (current->getRequestMessage().getVersion() < 10)
            state = ReadContent;
        else
            state = ReadStatusLine;
        return;
    }
    close();
    done(true);
}

void HttpConnection::readStatusLine(const boost::system::error_code& err)
{
    if (err && err != boost::asio::error::eof) {
        close();
        done(true);
        return;
    }
    const char* start = boost::asio::buffer_cast<const char*>(response.data());
    const char* end = start + response.size();
    const char* eol = std::find(start, end, '\n');
    if (eol == end) {
        if (err == boost::asio::error::eof) {
            retry();
            return;
        }
        line += std::string(start, response.size());
        response.consume(response.size());
        boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
        return;
    }
    ++eol;
    if (!line.empty()) {
        line += std::string(start, eol - start);
        response.consume(eol - start);
        start = line.c_str();
        eol = start + line.length();
    }

    if (3 <= getLogLevel())
        std::cerr << __func__ << ": " <<  std::string(start, eol - start) << '\n';

    const char* statusLine = current->getResponseMessage().parseStatusLine(start, eol);
    if (!statusLine) {
        close();
        done(true);
        return;
    }
    if (line.empty())
        response.consume(eol - start);
    line.clear();
    state = ReadHead;
    readHead(err);
}

void HttpConnection::readHead(const boost::system::error_code& err)
{
    if (err && err != boost::asio::error::eof) {
        close();
        done(true);
        return;
    }
    HttpResponseMessage& responseMessage = current->getResponseMessage();
    for (;;) {
        const char* start = boost::asio::buffer_cast<const char*>(response.data());
        const char* end = start + response.size();
        const char* eol = std::find(start, end, '\n');
        if (eol == end) {
            if (err == boost::asio::error::eof) {
                close();
                done(true);
                return;
            }
            line += std::string(start, response.size());
            response.consume(response.size());
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
        ++eol;
        if (!line.empty()) {
            line += std::string(start, eol - start);
            response.consume(eol - start);
            start = line.c_str();
            eol = start + line.length();
        }

        if (3 <= getLogLevel())
            std::cerr << __func__ << ": " <<  std::string(start, eol - start) << '\n';

        const char* header = parseCRLF(start, eol);
        if (*header == '\n') {
            if (line.empty())
                response.consume(eol - start);
            else
                line.clear();
            break;
        }
        header = responseMessage.parseHeader(start, eol);
        if (!header) {
            close();
            done(true);
            return;
        }
        if (line.empty())
            response.consume(eol - start);
        line.clear();
    }

    // TODO: handle every status code
    switch (responseMessage.getStatus()) {
    case 304:   // Not Modified
        current->constructResponseFromCache();
        done(false);
        if (!err)
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
        return;
    default:
        break;
    }
    if (responseMessage.isChunked()) {
        chunkCRLF = 0;
        octetCount = contentLength = 0;
        state = ReadChunk;
        readChunk(err);
    } else {
        octetCount = 0;
        contentLength = responseMessage.getContentLength();
        state = ReadContent;
        readContent(err);
    }
}

void HttpConnection::readContent(const boost::system::error_code& err)
{
    if (!err || err == boost::asio::error::eof) {
        std::fstream& content = current->getContent();
        if (!content.is_open()) {
            done(true);
            return;
        }
        bool completed = false;
        if (0 < response.size()) {
            if (!contentLength) {
                octetCount += response.size();
                content << &response;
            } else {
                unsigned long long length = std::min(static_cast<unsigned long long>(response.size()), contentLength - octetCount);
                content.write(boost::asio::buffer_cast<const char*>(response.data()), length);
                response.consume(length);
                octetCount += length;
                if (contentLength <= octetCount)
                    completed = true;
            }
        }
        if (!err && !completed) {
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
        content.flush();
    }
    if (err == boost::asio::error::eof) {
        close();
        if (contentLength < octetCount) {
            contentLength = octetCount;
            // TODO: set Content-length:
        }
        done(octetCount < contentLength);
        return;
    }
    done(err);
    state = CloseWait;
    boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
}

void HttpConnection::readChunk(const boost::system::error_code& err)
{
    if (!err || err == boost::asio::error::eof) {
        std::fstream& content = current->getContent();
        if (!content.is_open()) {
            done(true);
            return;
        }
        bool completed = false;
        while (0 < response.size()) {
            if (line[line.length() - 1] != '\n') {
                const char* chunk = boost::asio::buffer_cast<const char*>(response.data());
                const char* chunkEnd = chunk + response.size();
                auto p = std::find(chunk, chunkEnd, '\n');
                if (p == chunkEnd) {
                    line += std::string(chunk, response.size());
                    response.consume(response.size());
                    // TODO: check error and length
                } else {
                    line += std::string(chunk, p - chunk + 1);
                    response.consume(p - chunk + 1);
                    parseHexDigits(line.c_str(), line.c_str() + line.length(), chunkLength);
                    contentLength += chunkLength;
                    if (chunkLength == 0) {
                        if (line[0] != '0') {
                            done(true);
                            close();
                            return;
                        }
                        completed = true;
                        content.flush();
                        chunkCRLF = 1;
                    }
                }
            }
            if (!completed) {
                if (0 < response.size() && octetCount < contentLength) {
                    unsigned long long length = std::min(static_cast<unsigned long long>(response.size()), contentLength - octetCount);
                    content.write(boost::asio::buffer_cast<const char*>(response.data()), length);
                    response.consume(length);
                    octetCount += length;
                }
                while (0 < response.size() && contentLength <= octetCount) {
                    int c = response.sbumpc();
                    if (c == '\n') {
                        chunkCRLF = 0;
                        line.clear();
                        break;
                    } else if (c == '\r' && chunkCRLF == 0)
                        ++chunkCRLF;
                    else {
                        done(true);
                        close();
                        return;
                    }
                }
            } else {
                // TODO: process trailer
                state = ReadTrailer;
                readTrailer(err);
                return;
            }
        }
        if (!err) {
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
    }
    assert(err);
    done(err);
    close();
}

void HttpConnection::readTrailer(const boost::system::error_code& err)
{
    if (!err || err == boost::asio::error::eof) {
        while (0 < response.size()) {
            int c = response.sbumpc();
            if (c == '\n') {
                if (++chunkCRLF == 2) {
                    // TODO: set Content-length:
                    done(false);
                    if (err)
                        close();
                    else {
                        state = CloseWait;
                        boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
                    }
                    return;
                }
            } else if (c != '\r')
                chunkCRLF = 0;
        }
        if (!err) {
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
    }
    assert(err);
    done(err);
    close();
}

void HttpConnection::send(HttpRequest* request)
{
    if (current && current != request) {
        requests.push_back(request);
        return;
    }
    current = request;

    if (socket.is_open()) {
        sendRequest();
        return;
    }

    state = Resolving;
    boost::asio::ip::tcp::resolver::query query(hostname, port);
    HttpConnectionManager::getInstance().resolve(query,
                                                 boost::bind(&HttpConnection::handleResolve, this,
                                                             boost::asio::placeholders::error,
                                                             boost::asio::placeholders::iterator));
}

void HttpConnection::abort(HttpRequest* request)
{
    if (current != request) {
        requests.remove(request);
        request->notify(true);
        return;
    }
    close();
    done(true);
}

HttpConnection* HttpConnectionManager::getConnection(const std::string& hostname, const std::string& port)
{
    for (auto i = connections.begin(); i != connections.end(); ++i) {
        if ((*i)->hostname == hostname && (*i)->port == port)
            return *i;
    }
    HttpConnection* c = new(std::nothrow) HttpConnection(hostname, port);
    if (c)
        connections.push_back(c);
    return c;
}

void HttpConnectionManager::send(HttpRequest* request)
{
    URI uri(request->getRequestMessage().getURL());
    std::string hostname = uri.getHostname();
    std::string port = uri.getPort();
    HttpConnection* conn = getConnection(hostname, port);
    if (!conn)
        return;
    conn->send(request);
}

void HttpConnectionManager::abort(HttpRequest* request)
{
    URI uri(request->getRequestMessage().getURL());
    std::string hostname = uri.getHostname();
    std::string port = uri.getPort();
    HttpConnection* conn = getConnection(hostname, port);
    if (!conn)
        return;
    conn->abort(request);
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(HttpConnection::close) : Clean up the request buffer as well since it could still hold octets when a write operation has failed.<commit_after>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "HTTPConnection.h"

#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>

#include "url/URI.h"
#include "http/HTTPUtil.h"

#include "Test.util.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

using namespace http;

void HttpConnection::sendRequest()
{
    std::ostream stream(&request);
    stream << current->getRequestMessage().toString();
    stream << "\r\n";
    boost::asio::async_write(socket, request, boost::bind(&HttpConnection::handleWriteRequest, this, boost::asio::placeholders::error));
}

void HttpConnection::done(bool error)
{
    line.clear();
    if (current) {
        current->notify(error);
        current = 0;
    }
    if (!error) {
        if (!requests.empty()) {
            current = requests.front();
            requests.pop_front();
            sendRequest();
        }
    } else {
        while (!requests.empty()) {
            current = requests.front();
            requests.pop_front();
            current->notify(error);
        }
        current = 0;
    }
}

void HttpConnection::close()
{
    state = Closed;
    line.clear();
    retryCount = 0;
    socket.close();
    request.consume(request.size());
    response.consume(response.size());
}

void HttpConnection::retry()
{
    close();
    ++retryCount;
    if (retryCount < MaxRetryCount) {
        HttpRequest* request = current;
        current = 0;
        send(request);
    } else
        done(true);
}

void HttpConnection::handleResolve(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpointIterator)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << err << '\n';

    if (!err) {
        state = Resolved;
        boost::asio::ip::tcp::endpoint endpoint = *endpointIterator;
        socket.async_connect(endpoint, boost::bind(&HttpConnection::handleConnect, this, boost::asio::placeholders::error, ++endpointIterator));
        return;
    }
    done(true);
}

void HttpConnection::handleConnect(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpointIterator)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << err << '\n';

    if (!err) {
        state = Connected;
        if (current) {
            sendRequest();
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
        }
        return;
    }
    if (endpointIterator != boost::asio::ip::tcp::resolver::iterator()) {
        close();
        boost::asio::ip::tcp::endpoint endpoint = *endpointIterator;
        socket.async_connect(endpoint, boost::bind(&HttpConnection::handleConnect, this, boost::asio::placeholders::error, ++endpointIterator));
        return;
    }
    done(true);
}

void HttpConnection::handleRead(const boost::system::error_code& err)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << state << ' ' << err << '\n';

    switch (state) {
    case Closed:
        break;
    case ReadStatusLine:
        readStatusLine(err);
        break;
    case ReadHead:
        readHead(err);
        break;
    case ReadContent:
        readContent(err);
        break;
    case ReadChunk:
        readChunk(err);
        break;
    case ReadTrailer:
        readTrailer(err);
        break;
    case CloseWait:
        close();
        break;
    default:
        close();
        done(true);
        break;
    }
}

void HttpConnection::handleWriteRequest(const boost::system::error_code& err)
{
    if (3 <= getLogLevel())
        std::cerr << __func__ << ' ' << err <<  '\n';

    if (!err && current) {
        if (current->getRequestMessage().getVersion() < 10)
            state = ReadContent;
        else
            state = ReadStatusLine;
        return;
    }
    close();
    done(true);
}

void HttpConnection::readStatusLine(const boost::system::error_code& err)
{
    if (err && err != boost::asio::error::eof) {
        close();
        done(true);
        return;
    }
    const char* start = boost::asio::buffer_cast<const char*>(response.data());
    const char* end = start + response.size();
    const char* eol = std::find(start, end, '\n');
    if (eol == end) {
        if (err == boost::asio::error::eof) {
            retry();
            return;
        }
        line += std::string(start, response.size());
        response.consume(response.size());
        boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
        return;
    }
    ++eol;
    if (!line.empty()) {
        line += std::string(start, eol - start);
        response.consume(eol - start);
        start = line.c_str();
        eol = start + line.length();
    }

    if (3 <= getLogLevel())
        std::cerr << __func__ << ": " <<  std::string(start, eol - start) << '\n';

    const char* statusLine = current->getResponseMessage().parseStatusLine(start, eol);
    if (!statusLine) {
        close();
        done(true);
        return;
    }
    if (line.empty())
        response.consume(eol - start);
    line.clear();
    state = ReadHead;
    readHead(err);
}

void HttpConnection::readHead(const boost::system::error_code& err)
{
    if (err && err != boost::asio::error::eof) {
        close();
        done(true);
        return;
    }
    HttpResponseMessage& responseMessage = current->getResponseMessage();
    for (;;) {
        const char* start = boost::asio::buffer_cast<const char*>(response.data());
        const char* end = start + response.size();
        const char* eol = std::find(start, end, '\n');
        if (eol == end) {
            if (err == boost::asio::error::eof) {
                close();
                done(true);
                return;
            }
            line += std::string(start, response.size());
            response.consume(response.size());
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
        ++eol;
        if (!line.empty()) {
            line += std::string(start, eol - start);
            response.consume(eol - start);
            start = line.c_str();
            eol = start + line.length();
        }

        if (3 <= getLogLevel())
            std::cerr << __func__ << ": " <<  std::string(start, eol - start) << '\n';

        const char* header = parseCRLF(start, eol);
        if (*header == '\n') {
            if (line.empty())
                response.consume(eol - start);
            else
                line.clear();
            break;
        }
        header = responseMessage.parseHeader(start, eol);
        if (!header) {
            close();
            done(true);
            return;
        }
        if (line.empty())
            response.consume(eol - start);
        line.clear();
    }

    // TODO: handle every status code
    switch (responseMessage.getStatus()) {
    case 304:   // Not Modified
        current->constructResponseFromCache();
        done(false);
        if (!err)
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
        return;
    default:
        break;
    }
    if (responseMessage.isChunked()) {
        chunkCRLF = 0;
        octetCount = contentLength = 0;
        state = ReadChunk;
        readChunk(err);
    } else {
        octetCount = 0;
        contentLength = responseMessage.getContentLength();
        state = ReadContent;
        readContent(err);
    }
}

void HttpConnection::readContent(const boost::system::error_code& err)
{
    if (!err || err == boost::asio::error::eof) {
        std::fstream& content = current->getContent();
        if (!content.is_open()) {
            done(true);
            return;
        }
        bool completed = false;
        if (0 < response.size()) {
            if (!contentLength) {
                octetCount += response.size();
                content << &response;
            } else {
                unsigned long long length = std::min(static_cast<unsigned long long>(response.size()), contentLength - octetCount);
                content.write(boost::asio::buffer_cast<const char*>(response.data()), length);
                response.consume(length);
                octetCount += length;
                if (contentLength <= octetCount)
                    completed = true;
            }
        }
        if (!err && !completed) {
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
        content.flush();
    }
    if (err == boost::asio::error::eof) {
        close();
        if (contentLength < octetCount) {
            contentLength = octetCount;
            // TODO: set Content-length:
        }
        done(octetCount < contentLength);
        return;
    }
    done(err);
    state = CloseWait;
    boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
}

void HttpConnection::readChunk(const boost::system::error_code& err)
{
    if (!err || err == boost::asio::error::eof) {
        std::fstream& content = current->getContent();
        if (!content.is_open()) {
            done(true);
            return;
        }
        bool completed = false;
        while (0 < response.size()) {
            if (line[line.length() - 1] != '\n') {
                const char* chunk = boost::asio::buffer_cast<const char*>(response.data());
                const char* chunkEnd = chunk + response.size();
                auto p = std::find(chunk, chunkEnd, '\n');
                if (p == chunkEnd) {
                    line += std::string(chunk, response.size());
                    response.consume(response.size());
                    // TODO: check error and length
                } else {
                    line += std::string(chunk, p - chunk + 1);
                    response.consume(p - chunk + 1);
                    parseHexDigits(line.c_str(), line.c_str() + line.length(), chunkLength);
                    contentLength += chunkLength;
                    if (chunkLength == 0) {
                        if (line[0] != '0') {
                            done(true);
                            close();
                            return;
                        }
                        completed = true;
                        content.flush();
                        chunkCRLF = 1;
                    }
                }
            }
            if (!completed) {
                if (0 < response.size() && octetCount < contentLength) {
                    unsigned long long length = std::min(static_cast<unsigned long long>(response.size()), contentLength - octetCount);
                    content.write(boost::asio::buffer_cast<const char*>(response.data()), length);
                    response.consume(length);
                    octetCount += length;
                }
                while (0 < response.size() && contentLength <= octetCount) {
                    int c = response.sbumpc();
                    if (c == '\n') {
                        chunkCRLF = 0;
                        line.clear();
                        break;
                    } else if (c == '\r' && chunkCRLF == 0)
                        ++chunkCRLF;
                    else {
                        done(true);
                        close();
                        return;
                    }
                }
            } else {
                // TODO: process trailer
                state = ReadTrailer;
                readTrailer(err);
                return;
            }
        }
        if (!err) {
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
    }
    assert(err);
    done(err);
    close();
}

void HttpConnection::readTrailer(const boost::system::error_code& err)
{
    if (!err || err == boost::asio::error::eof) {
        while (0 < response.size()) {
            int c = response.sbumpc();
            if (c == '\n') {
                if (++chunkCRLF == 2) {
                    // TODO: set Content-length:
                    done(false);
                    if (err)
                        close();
                    else {
                        state = CloseWait;
                        boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
                    }
                    return;
                }
            } else if (c != '\r')
                chunkCRLF = 0;
        }
        if (!err) {
            boost::asio::async_read(socket, response, boost::asio::transfer_at_least(1), boost::bind(&HttpConnection::handleRead, this, boost::asio::placeholders::error));
            return;
        }
    }
    assert(err);
    done(err);
    close();
}

void HttpConnection::send(HttpRequest* request)
{
    if (current) {
        assert(current != request);
        requests.push_back(request);
        return;
    }
    current = request;

    if (socket.is_open()) {
        sendRequest();
        return;
    }

    state = Resolving;
    boost::asio::ip::tcp::resolver::query query(hostname, port);
    HttpConnectionManager::getInstance().resolve(query,
                                                 boost::bind(&HttpConnection::handleResolve, this,
                                                             boost::asio::placeholders::error,
                                                             boost::asio::placeholders::iterator));
}

void HttpConnection::abort(HttpRequest* request)
{
    if (current != request) {
        requests.remove(request);
        request->notify(true);
        return;
    }
    close();
    done(true);
}

HttpConnection* HttpConnectionManager::getConnection(const std::string& hostname, const std::string& port)
{
    for (auto i = connections.begin(); i != connections.end(); ++i) {
        if ((*i)->hostname == hostname && (*i)->port == port)
            return *i;
    }
    HttpConnection* c = new(std::nothrow) HttpConnection(hostname, port);
    if (c)
        connections.push_back(c);
    return c;
}

void HttpConnectionManager::send(HttpRequest* request)
{
    URI uri(request->getRequestMessage().getURL());
    std::string hostname = uri.getHostname();
    std::string port = uri.getPort();
    HttpConnection* conn = getConnection(hostname, port);
    if (!conn)
        return;
    conn->send(request);
}

void HttpConnectionManager::abort(HttpRequest* request)
{
    URI uri(request->getRequestMessage().getURL());
    std::string hostname = uri.getHostname();
    std::string port = uri.getPort();
    HttpConnection* conn = getConnection(hostname, port);
    if (!conn)
        return;
    conn->abort(request);
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include "SpaghettiInfillPathGenerator.h"
#include "../infill.h"
#include "../FffGcodeWriter.h"

namespace cura {

bool SpaghettiInfillPathGenerator::processSpaghettiInfill(const SliceDataStorage& storage, const FffGcodeWriter& fff_gcode_writer, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const int extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, int infill_line_distance, int infill_overlap, int infill_angle, const Point& infill_origin)
{
    if (extruder_nr != mesh.getSettingAsExtruderNr("infill_extruder_nr"))
    {
        return false;
    }
    bool added_something = false;
    const GCodePathConfig& config = mesh_config.infill_config[0]; //Don't use gradual infill, so always take the 0th element.
    const EFillMethod pattern = mesh.getSettingAsFillMethod("infill_pattern");
    const bool zig_zaggify_infill = mesh.getSettingBoolean("zig_zaggify_infill");
    const unsigned int infill_line_width = config.getLineWidth();
    const int64_t infill_shift = 0;
    const int64_t outline_offset = 0;
    const double layer_height_mm = (gcode_layer.getLayerNr() == 0) ? mesh.getSettingInMillimeters("layer_height_0") : mesh.getSettingInMillimeters("layer_height");

    // For each part on this layer which is used to fill that part and parts below:
    for (const std::pair<Polygons, double>& filling_area : part.spaghetti_infill_volumes)
    {
        Polygons infill_lines;
        Polygons infill_polygons;

        const Polygons& area = filling_area.first; // Area of the top within which to move while extruding (might be empty if the spaghetti_inset was too large)
        const double total_volume = filling_area.second * mesh.getSettingAsRatio("spaghetti_flow") + mesh.getSettingInCubicMillimeters("spaghetti_infill_extra_volume"); // volume to be extruded
        if (total_volume <= 0.0)
        {
            continue;
        }

        // generate zigzag print head paths
        Polygons* perimeter_gaps_output = nullptr;
        const bool connected_zigzags = true;
        const bool use_endpieces = false;
        Infill infill_comp(pattern, zig_zaggify_infill, area, outline_offset
            , infill_line_width, infill_line_distance, infill_overlap, infill_angle, gcode_layer.z, infill_shift, infill_origin, perimeter_gaps_output, connected_zigzags, use_endpieces
            , mesh.getSettingBoolean("cross_infill_apply_pockets_alternatingly"), mesh.getSettingInMicrons("cross_infill_pocket_size"));
        // cross_fill_patterns is only generated when spaghetti infill is not used,
        // so we pass nullptr here.
        infill_comp.generate(infill_polygons, infill_lines, nullptr, &mesh);

        // add paths to plan with a higher flow ratio in order to extrude the required amount.
        const coord_t total_length = infill_polygons.polygonLength() + infill_lines.polyLineLength();
        if (total_length > 0)
        { // zigzag path generation actually generated paths
            // calculate the normal volume extruded when using the layer height and line width to calculate extrusion
            const double normal_volume = INT2MM(INT2MM(total_length * infill_line_width)) * layer_height_mm;
            assert(normal_volume > 0.0);
            const float flow_ratio = total_volume / normal_volume;
            assert(flow_ratio / mesh.getSettingAsRatio("spaghetti_flow") >= 0.9);
            assert(!std::isnan(flow_ratio) && !std::isinf(flow_ratio));

            if (!infill_polygons.empty() || !infill_lines.empty())
            {
                added_something = true;
                fff_gcode_writer.setExtruder_addPrime(storage, gcode_layer, extruder_nr);
                gcode_layer.addPolygonsByOptimizer(infill_polygons, config, nullptr, ZSeamConfig(), 0, false, flow_ratio);
                switch(pattern)
                {
                    case EFillMethod::GRID:
                    case EFillMethod::LINES:
                    case EFillMethod::TRIANGLES:
                    case EFillMethod::CUBIC:
                    case EFillMethod::TETRAHEDRAL:
                    case EFillMethod::QUARTER_CUBIC:
                    case EFillMethod::CUBICSUBDIV:
                        gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::Lines, mesh.getSettingInMicrons("infill_wipe_dist"), flow_ratio);
                        break;
                    case EFillMethod::CROSS:
                    case EFillMethod::CROSS_3D:
                        if (mesh.getSettingBoolean("zig_zaggify_infill"))
                        {
                            gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::PolyLines, 0, flow_ratio);
                        }
                        else
                        {
                            gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::Lines, mesh.getSettingInMicrons("infill_wipe_dist"), flow_ratio);
                        }
                    case EFillMethod::ZIG_ZAG:
                        gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::PolyLines, 0, flow_ratio);
                        break;
                    default:
                        gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::Lines, 0, flow_ratio);
                        break;
                }
            }
        }
        else
        { // zigzag path generation couldn't generate paths, probably because the area was too small
            // generate small path near the middle of the filling area
            // note that we need a path with positive length because that is currently the only way to insert an extrusion in a layer plan
            constexpr int path_length = 10;
            Point middle = AABB(area).getMiddle();
            if (!area.inside(middle))
            {
                PolygonUtils::ensureInsideOrOutside(area, middle, infill_line_width / 2);
            }
            const double normal_volume = INT2MM(INT2MM(path_length * infill_line_width)) * layer_height_mm;
            const float flow_ratio = total_volume / normal_volume;
            gcode_layer.addTravel(middle);
            gcode_layer.addExtrusionMove(middle + Point(0, path_length), config, SpaceFillType::Lines, flow_ratio);
        }
    }
    return added_something;
}

}//namespace cura
<commit_msg>Prevent fallthrough from Cross3D to zigzag<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include "SpaghettiInfillPathGenerator.h"
#include "../infill.h"
#include "../FffGcodeWriter.h"

namespace cura {

bool SpaghettiInfillPathGenerator::processSpaghettiInfill(const SliceDataStorage& storage, const FffGcodeWriter& fff_gcode_writer, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const int extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, int infill_line_distance, int infill_overlap, int infill_angle, const Point& infill_origin)
{
    if (extruder_nr != mesh.getSettingAsExtruderNr("infill_extruder_nr"))
    {
        return false;
    }
    bool added_something = false;
    const GCodePathConfig& config = mesh_config.infill_config[0]; //Don't use gradual infill, so always take the 0th element.
    const EFillMethod pattern = mesh.getSettingAsFillMethod("infill_pattern");
    const bool zig_zaggify_infill = mesh.getSettingBoolean("zig_zaggify_infill");
    const unsigned int infill_line_width = config.getLineWidth();
    const int64_t infill_shift = 0;
    const int64_t outline_offset = 0;
    const double layer_height_mm = (gcode_layer.getLayerNr() == 0) ? mesh.getSettingInMillimeters("layer_height_0") : mesh.getSettingInMillimeters("layer_height");

    // For each part on this layer which is used to fill that part and parts below:
    for (const std::pair<Polygons, double>& filling_area : part.spaghetti_infill_volumes)
    {
        Polygons infill_lines;
        Polygons infill_polygons;

        const Polygons& area = filling_area.first; // Area of the top within which to move while extruding (might be empty if the spaghetti_inset was too large)
        const double total_volume = filling_area.second * mesh.getSettingAsRatio("spaghetti_flow") + mesh.getSettingInCubicMillimeters("spaghetti_infill_extra_volume"); // volume to be extruded
        if (total_volume <= 0.0)
        {
            continue;
        }

        // generate zigzag print head paths
        Polygons* perimeter_gaps_output = nullptr;
        const bool connected_zigzags = true;
        const bool use_endpieces = false;
        Infill infill_comp(pattern, zig_zaggify_infill, area, outline_offset
            , infill_line_width, infill_line_distance, infill_overlap, infill_angle, gcode_layer.z, infill_shift, infill_origin, perimeter_gaps_output, connected_zigzags, use_endpieces
            , mesh.getSettingBoolean("cross_infill_apply_pockets_alternatingly"), mesh.getSettingInMicrons("cross_infill_pocket_size"));
        // cross_fill_patterns is only generated when spaghetti infill is not used,
        // so we pass nullptr here.
        infill_comp.generate(infill_polygons, infill_lines, nullptr, &mesh);

        // add paths to plan with a higher flow ratio in order to extrude the required amount.
        const coord_t total_length = infill_polygons.polygonLength() + infill_lines.polyLineLength();
        if (total_length > 0)
        { // zigzag path generation actually generated paths
            // calculate the normal volume extruded when using the layer height and line width to calculate extrusion
            const double normal_volume = INT2MM(INT2MM(total_length * infill_line_width)) * layer_height_mm;
            assert(normal_volume > 0.0);
            const float flow_ratio = total_volume / normal_volume;
            assert(flow_ratio / mesh.getSettingAsRatio("spaghetti_flow") >= 0.9);
            assert(!std::isnan(flow_ratio) && !std::isinf(flow_ratio));

            if (!infill_polygons.empty() || !infill_lines.empty())
            {
                added_something = true;
                fff_gcode_writer.setExtruder_addPrime(storage, gcode_layer, extruder_nr);
                gcode_layer.addPolygonsByOptimizer(infill_polygons, config, nullptr, ZSeamConfig(), 0, false, flow_ratio);
                switch(pattern)
                {
                    case EFillMethod::GRID:
                    case EFillMethod::LINES:
                    case EFillMethod::TRIANGLES:
                    case EFillMethod::CUBIC:
                    case EFillMethod::TETRAHEDRAL:
                    case EFillMethod::QUARTER_CUBIC:
                    case EFillMethod::CUBICSUBDIV:
                        gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::Lines, mesh.getSettingInMicrons("infill_wipe_dist"), flow_ratio);
                        break;
                    case EFillMethod::CROSS:
                    case EFillMethod::CROSS_3D:
                        if (mesh.getSettingBoolean("zig_zaggify_infill"))
                        {
                            gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::PolyLines, 0, flow_ratio);
                        }
                        else
                        {
                            gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::Lines, mesh.getSettingInMicrons("infill_wipe_dist"), flow_ratio);
                        }
                        break;
                    case EFillMethod::ZIG_ZAG:
                        gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::PolyLines, 0, flow_ratio);
                        break;
                    default:
                        gcode_layer.addLinesByOptimizer(infill_lines, config, SpaceFillType::Lines, 0, flow_ratio);
                        break;
                }
            }
        }
        else
        { // zigzag path generation couldn't generate paths, probably because the area was too small
            // generate small path near the middle of the filling area
            // note that we need a path with positive length because that is currently the only way to insert an extrusion in a layer plan
            constexpr int path_length = 10;
            Point middle = AABB(area).getMiddle();
            if (!area.inside(middle))
            {
                PolygonUtils::ensureInsideOrOutside(area, middle, infill_line_width / 2);
            }
            const double normal_volume = INT2MM(INT2MM(path_length * infill_line_width)) * layer_height_mm;
            const float flow_ratio = total_volume / normal_volume;
            gcode_layer.addTravel(middle);
            gcode_layer.addExtrusionMove(middle + Point(0, path_length), config, SpaceFillType::Lines, flow_ratio);
        }
    }
    return added_something;
}

}//namespace cura
<|endoftext|>


<commit_before>/*
The MIT License

Copyright (c) 2008 Dennis Mllegaard Pedersen <dennis@moellegaard.dk>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <wx/url.h>
#include <wx/log.h>
#include <wx/intl.h>
#include <wx/tokenzr.h>
#include <wx/listimpl.cpp>
#include <wx/utils.h>

#include "main.h"
#include "config.h"
#include "listserverhandler.h"
#include "serverparser.h"

/*
 * Serverlist is a text/plain response from bzflag.org servers. Each line describes a single
 * bzflag server (bzfs). The format is:
 * hostname:port version hexcoded-info ip name
 * where:
 *   - hostname:port   is the connection info
 *   - version         is the protcol version. currently BZFS0026 is used
 *   - hexcoded info   contains some server details (ctf,ffa.., max allowed players)
 *                      etc.  version-specific
 *   - ip              ip-address of the hostname
 *   - name            The remaining chars of the line, is the servername as
 *                      shown in "Find server" option in bzfs
 */
WX_DEFINE_LIST(ServerList);

ListServerHandler::ListServerHandler() : version(0) {
}

ListServerHandler::~ListServerHandler() {
	this->ClearList();
}

void ListServerHandler::GetServerList(wxArrayString& favs,wxArrayString& recent) {
	wxBusyCursor wait;
	BZLauncherApp& app = wxGetApp();

	app.SetStatusText(_("Fetching data from list-server..."));

	// TODO: Dont clear the list just yet. keep it while building the
	// newer version and after doing this, delete it. This will allow
	// the Ping-classes to reuse ping-measurements without needing
	// to reping them.
	this->ClearList();
	this->version++;

	if( this->GetListServerResponse() ) {
		app.SetStatusText(_("Parsing data from list-server..."));
		wxStringTokenizer tok(this->rawResponse, _T("\r\n"));

		while(tok.HasMoreTokens()) {
			wxString token = tok.GetNextToken();

			this->ParseLine(token, favs, recent);
		}
	}
	else {
		wxLogError(_("Can't connect to listserver!"));
	}
	app.SetStatusText(wxString::Format(_("Found %d server(s)"), this->serverList.GetCount()));

}

bool ListServerHandler::ParseLine(const wxString& line, wxArrayString& favs,wxArrayString& recent) {
	Server* s = new Server;

	s->fullyParsed  = false;
	s->favorite     = false;

	wxStringTokenizer tok(line, _T(" "));

	int i = 0;
	long port;
	wxString host;
	while(tok.HasMoreTokens()) {
		wxString token = tok.GetNextToken();
		switch(i) {
		case 0:	{ // servername:port
			s->name = token;

			port = 5154;
			host = token;
			int pos;

			if((pos = token.Find(':',true)) != wxNOT_FOUND) {
				if(!token.Mid(pos+1).ToLong(&port))
					port = 5154;
				host = token.Mid(0,pos-1);
			}

			}
			break;
		case 1:  // version
			s->protocolVersion = token;
			break;
		case 2:  // Hex info
			{
				ServerHexParser* p = ServerHexParser::GetParser(s->protocolVersion);
				if(p) {
					p->parse(token,*s);
					delete p;
				}
			}
			break;
		case 3:
			{
				wxIPV4address ip;
				ip.Hostname(token);
				ip.Service(port);
				s->setIP(ip);
				s->longName.value += tok.GetString();
			}
			break;
		}
		i++;
	}

	s->favorite = (favs.Index(s->name()) != wxNOT_FOUND);
	s->recent   = (recent.Index(s->name()) != wxNOT_FOUND);

	this->serverList.Append(s);

	return true;
}

bool ListServerHandler::GetListServerResponse() {
	wxFileSystem	fs;
	wxFSFile*		listserv = NULL;
	wxString		url;
	int				c = 0;
	bool			r = false;

	while( listserv == NULL && (url = appConfig.getListServerURL(c++)) && !url.IsEmpty())
		listserv = fs.OpenFile(url);

	if(listserv) {
		wxInputStream *in_stream;
		in_stream = listserv->GetStream();

		if(in_stream) {
			char		buffer[1024];

			this->rawResponse.Clear();

			while(in_stream->Read(buffer,1024).LastRead()) {
				this->rawResponse << wxString::From8BitData(buffer,in_stream->LastRead());
			}

			r = true;
		}
		else {
			wxLogMessage(_("in_stream == null"));
		}

		delete listserv;
	}

	return r;
}

void ListServerHandler::ClearList() {
	ServerList::iterator i;
	for(i = this->serverList.begin(); i != this->serverList.end(); ++i) {
		Server*	current = *i;
		delete current;
	}

	this->serverList.Clear();
}

Server* ListServerHandler::FindByName(const wxString& n) {
	ServerList::iterator i;
	for(i = this->serverList.begin(); i != this->serverList.end(); ++i) {
		Server*	current = *i;

		if(n.Cmp(current->name()) == 0)
			return current;
	}

	return NULL;
}

ServerResultSet ListServerHandler::Search(const Query& query) {
	ServerResultSet	resultSet;

	for(ServerList::iterator i = this->serverList.begin(); i != this->serverList.end(); ++i) {
		Server*	current = *i;

		if(query == const_cast<Server*>(current)) {
			resultSet.push_back(current);
		}
	}

	return resultSet;
}
<commit_msg>Disable this, so we don't hit listserver twice at each run<commit_after>/*
The MIT License

Copyright (c) 2008 Dennis Mllegaard Pedersen <dennis@moellegaard.dk>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <wx/url.h>
#include <wx/log.h>
#include <wx/intl.h>
#include <wx/tokenzr.h>
#include <wx/listimpl.cpp>
#include <wx/utils.h>

#include "main.h"
#include "config.h"
#include "listserverhandler.h"
#include "serverparser.h"

/*
 * Serverlist is a text/plain response from bzflag.org servers. Each line describes a single
 * bzflag server (bzfs). The format is:
 * hostname:port version hexcoded-info ip name
 * where:
 *   - hostname:port   is the connection info
 *   - version         is the protcol version. currently BZFS0026 is used
 *   - hexcoded info   contains some server details (ctf,ffa.., max allowed players)
 *                      etc.  version-specific
 *   - ip              ip-address of the hostname
 *   - name            The remaining chars of the line, is the servername as
 *                      shown in "Find server" option in bzfs
 */
WX_DEFINE_LIST(ServerList);

ListServerHandler::ListServerHandler() : version(0) {
}

ListServerHandler::~ListServerHandler() {
	this->ClearList();
}

void ListServerHandler::GetServerList(wxArrayString& favs,wxArrayString& recent) {
return;	// DISABLED
	wxBusyCursor wait;
	BZLauncherApp& app = wxGetApp();

	app.SetStatusText(_("Fetching data from list-server..."));

	// TODO: Dont clear the list just yet. keep it while building the
	// newer version and after doing this, delete it. This will allow
	// the Ping-classes to reuse ping-measurements without needing
	// to reping them.
	this->ClearList();
	this->version++;

	if( this->GetListServerResponse() ) {
		app.SetStatusText(_("Parsing data from list-server..."));
		wxStringTokenizer tok(this->rawResponse, _T("\r\n"));

		while(tok.HasMoreTokens()) {
			wxString token = tok.GetNextToken();

			this->ParseLine(token, favs, recent);
		}
	}
	else {
		wxLogError(_("Can't connect to listserver!"));
	}
	app.SetStatusText(wxString::Format(_("Found %d server(s)"), this->serverList.GetCount()));

}

bool ListServerHandler::ParseLine(const wxString& line, wxArrayString& favs,wxArrayString& recent) {
	Server* s = new Server;

	s->fullyParsed  = false;
	s->favorite     = false;

	wxStringTokenizer tok(line, _T(" "));

	int i = 0;
	long port;
	wxString host;
	while(tok.HasMoreTokens()) {
		wxString token = tok.GetNextToken();
		switch(i) {
		case 0:	{ // servername:port
			s->name = token;

			port = 5154;
			host = token;
			int pos;

			if((pos = token.Find(':',true)) != wxNOT_FOUND) {
				if(!token.Mid(pos+1).ToLong(&port))
					port = 5154;
				host = token.Mid(0,pos-1);
			}

			}
			break;
		case 1:  // version
			s->protocolVersion = token;
			break;
		case 2:  // Hex info
			{
				ServerHexParser* p = ServerHexParser::GetParser(s->protocolVersion);
				if(p) {
					p->parse(token,*s);
					delete p;
				}
			}
			break;
		case 3:
			{
				wxIPV4address ip;
				ip.Hostname(token);
				ip.Service(port);
				s->setIP(ip);
				s->longName.value += tok.GetString();
			}
			break;
		}
		i++;
	}

	s->favorite = (favs.Index(s->name()) != wxNOT_FOUND);
	s->recent   = (recent.Index(s->name()) != wxNOT_FOUND);

	this->serverList.Append(s);

	return true;
}

bool ListServerHandler::GetListServerResponse() {
	wxFileSystem	fs;
	wxFSFile*		listserv = NULL;
	wxString		url;
	int				c = 0;
	bool			r = false;

	while( listserv == NULL && (url = appConfig.getListServerURL(c++)) && !url.IsEmpty())
		listserv = fs.OpenFile(url);

	if(listserv) {
		wxInputStream *in_stream;
		in_stream = listserv->GetStream();

		if(in_stream) {
			char		buffer[1024];

			this->rawResponse.Clear();

			while(in_stream->Read(buffer,1024).LastRead()) {
				this->rawResponse << wxString::From8BitData(buffer,in_stream->LastRead());
			}

			r = true;
		}
		else {
			wxLogMessage(_("in_stream == null"));
		}

		delete listserv;
	}

	return r;
}

void ListServerHandler::ClearList() {
	ServerList::iterator i;
	for(i = this->serverList.begin(); i != this->serverList.end(); ++i) {
		Server*	current = *i;
		delete current;
	}

	this->serverList.Clear();
}

Server* ListServerHandler::FindByName(const wxString& n) {
	ServerList::iterator i;
	for(i = this->serverList.begin(); i != this->serverList.end(); ++i) {
		Server*	current = *i;

		if(n.Cmp(current->name()) == 0)
			return current;
	}

	return NULL;
}

ServerResultSet ListServerHandler::Search(const Query& query) {
	ServerResultSet	resultSet;

	for(ServerList::iterator i = this->serverList.begin(); i != this->serverList.end(); ++i) {
		Server*	current = *i;

		if(query == const_cast<Server*>(current)) {
			resultSet.push_back(current);
		}
	}

	return resultSet;
}
<|endoftext|>


<commit_before>#include "LinearPanel.h"
#include <algorithm>

using namespace std;

LinearPanel::LinearPanel()
{
	contentSize.w = 0;
	contentSize.h = 0;
	orientation = OrientationHorizontal;
}

LinearPanel::~LinearPanel()
{
}

bool LinearPanel::OnInitialize()
{
	ScrollView::SetOrientation(orientation);
	return true;
}

void LinearPanel::OnLayoutChange()
{
	Position childOffset = Position(0, 0);
	contentSize = Size(0, 0);

	Size* childSizes = new Size[children.size()];

	if ((size.w == SIZE_MATCH_PARENT || size.w > 0) && orientation == OrientationVertical)
		contentSize.w = calculatedSize.w;
	if ((size.h == SIZE_MATCH_PARENT || size.h > 0) && orientation == OrientationHorizontal)
		contentSize.h = calculatedSize.h;

	// Position children
	for (int i = 0; i < children.size(); i++)
	{
		View* v = children.at(i);

		Box childMargin = v->GetLayoutMargin();
		Size sizeAreaForChild;
		sizeAreaForChild.w = max(size.w == SIZE_WRAP_CONTENT ? -1 : calculatedSize.w - (childMargin.left + childMargin.right), 0);
		sizeAreaForChild.h = max(size.h == SIZE_WRAP_CONTENT ? -1 : calculatedSize.h - (childMargin.top + childMargin.bottom), 0);
		Size childSize = v->CalculateLayout(childOffset, sizeAreaForChild);
		Size childSizeIncMargins = childSize + Size(childMargin.left + childMargin.right, childMargin.top + childMargin.bottom);
		childSizes[i] = childSizeIncMargins;

		v->SetRelativePosition(childOffset + Position(childMargin.left, childMargin.top));

		if (orientation == OrientationHorizontal)
		{
			childOffset.x += childSizeIncMargins.w;
			contentSize.w += childSizeIncMargins.w;
			if (size.h == SIZE_WRAP_CONTENT)
				contentSize.h = max(contentSize.h, childSizeIncMargins.h);
		}
		else
		{
			childOffset.y += childSizeIncMargins.h;
			contentSize.h += childSizeIncMargins.h;
			if (size.w == SIZE_WRAP_CONTENT)
				contentSize.w = max(contentSize.w, childSizeIncMargins.w);
		}
	}

	// Adjust child positions for gravity
	for (int i = 0; i < children.size(); i++)
	{
		View* v = children.at(i);

		Size containerSize;
		if (orientation == OrientationHorizontal)
		{
			containerSize.w = childSizes[i].w;
			containerSize.h = contentSize.h;
		}
		else
		{
			containerSize.w = contentSize.w;
			containerSize.h = childSizes[i].h;
		}

		Position gravityOffset = GetGravityOffset(childSizes[i], containerSize, children[i]->GetLayoutGravity());
		v->SetRelativePosition(v->GetRelativePosition() + gravityOffset);
	}

	delete[] childSizes;
}

View* LinearPanel::Copy()
{
	LinearPanel* view = new LinearPanel();

	CopyBase(view);
	view->SetOrientation(orientation);

	return view;
}

Orientation LinearPanel::GetOrientation()
{
	return orientation;
}

void LinearPanel::SetOrientation(Orientation orientation)
{
	this->orientation = orientation;
}

bool LinearPanel::SetProperty(string name, string value)
{
	bool propertyHandled = View::SetProperty(name, value);

	if (propertyHandled)
		return true;

	if (name == "orientation")
	{
		if (value == "horizontal")
			SetOrientation(OrientationHorizontal);
		else if (value == "vertical")
			SetOrientation(OrientationVertical);
		else
			throw runtime_error("invalid orientation");

		return true;
	}

	return false;
}

Position LinearPanel::GetPositionForItemIndex(int elementNo)
{
	Position position = Position(-1, -1);

	if (elementNo < 0 || elementNo >= children.size())
		return position;

	if (orientation == OrientationHorizontal)
	{
		position.x = elementNo;
		position.y = 0;
	}
	else
	{
		position.x = 0;
		position.y = elementNo;
	}

	return position;
}

int LinearPanel::GetItemIndexForPosition(Position position)
{
	if (orientation == OrientationHorizontal)
	{
		if (position.x < 0 || position.x >= children.size())
			return -1;

		if (position.y != 0)
			return -1;

		return position.x;
	}
	else
	{
		if (position.x != 0)
			return -1;

		if (position.y < 0 || position.y >= children.size())
			return -1;

		return position.y;
	}
}

View* LinearPanel::GetSelectedItem()
{
	return children[selectedIndex];
}

View* LinearPanel::SelectNext(Direction direction)
{
	if (children.size() == 0)
		return NULL;

	int dx = 0;
	int dy = 0;

	switch (direction)
	{
	case DirectionUp:
		dy = -1;
		break;
	case DirectionDown:
		dy = 1;
		break;
	case DirectionLeft:
		dx = -1;
		break;
	case DirectionRight:
		dx = 1;
		break;
	}

	int origIndex = selectedIndex;
	int index;

	if (orientation == OrientationHorizontal)
	{
		if (origIndex + dx < 0 || origIndex + dx >= children.size())
			return NULL;

		if (dy != 0)
			return NULL;

		index += dx;
	}

	if (orientation == OrientationVertical)
	{
		if (dx != 0)
			return NULL;

		if (origIndex + dy < 0 || origIndex + dy >= children.size())
			return NULL;

		index += dy;
	}

	// A new selection was made
	SelectByIndex(index);

	return children[index];
}

View* LinearPanel::Select(Position position)
{
	PropagateStateChange("stateSelected", "false");

	int index = GetItemIndexForPosition(position);
	if (index >= 0 && index < children.size())
	{
		children[index]->PropagateStateChange("stateSelected", "true");
		ScrollTo(children[index]);
		return children[index];
	}
	else
	{
		return NULL;
	}
}

void LinearPanel::OnSelectionChanged()
{
	ScrollTo(children[selectedIndex]);
}
<commit_msg>* Fix uninitialized variable<commit_after>#include "LinearPanel.h"
#include <algorithm>

using namespace std;

LinearPanel::LinearPanel()
{
	contentSize.w = 0;
	contentSize.h = 0;
	orientation = OrientationHorizontal;
}

LinearPanel::~LinearPanel()
{
}

bool LinearPanel::OnInitialize()
{
	ScrollView::SetOrientation(orientation);
	return true;
}

void LinearPanel::OnLayoutChange()
{
	Position childOffset = Position(0, 0);
	contentSize = Size(0, 0);

	Size* childSizes = new Size[children.size()];

	if ((size.w == SIZE_MATCH_PARENT || size.w > 0) && orientation == OrientationVertical)
		contentSize.w = calculatedSize.w;
	if ((size.h == SIZE_MATCH_PARENT || size.h > 0) && orientation == OrientationHorizontal)
		contentSize.h = calculatedSize.h;

	// Position children
	for (int i = 0; i < children.size(); i++)
	{
		View* v = children.at(i);

		Box childMargin = v->GetLayoutMargin();
		Size sizeAreaForChild;
		sizeAreaForChild.w = max(size.w == SIZE_WRAP_CONTENT ? -1 : calculatedSize.w - (childMargin.left + childMargin.right), 0);
		sizeAreaForChild.h = max(size.h == SIZE_WRAP_CONTENT ? -1 : calculatedSize.h - (childMargin.top + childMargin.bottom), 0);
		Size childSize = v->CalculateLayout(childOffset, sizeAreaForChild);
		Size childSizeIncMargins = childSize + Size(childMargin.left + childMargin.right, childMargin.top + childMargin.bottom);
		childSizes[i] = childSizeIncMargins;

		v->SetRelativePosition(childOffset + Position(childMargin.left, childMargin.top));

		if (orientation == OrientationHorizontal)
		{
			childOffset.x += childSizeIncMargins.w;
			contentSize.w += childSizeIncMargins.w;
			if (size.h == SIZE_WRAP_CONTENT)
				contentSize.h = max(contentSize.h, childSizeIncMargins.h);
		}
		else
		{
			childOffset.y += childSizeIncMargins.h;
			contentSize.h += childSizeIncMargins.h;
			if (size.w == SIZE_WRAP_CONTENT)
				contentSize.w = max(contentSize.w, childSizeIncMargins.w);
		}
	}

	// Adjust child positions for gravity
	for (int i = 0; i < children.size(); i++)
	{
		View* v = children.at(i);

		Size containerSize;
		if (orientation == OrientationHorizontal)
		{
			containerSize.w = childSizes[i].w;
			containerSize.h = contentSize.h;
		}
		else
		{
			containerSize.w = contentSize.w;
			containerSize.h = childSizes[i].h;
		}

		Position gravityOffset = GetGravityOffset(childSizes[i], containerSize, children[i]->GetLayoutGravity());
		v->SetRelativePosition(v->GetRelativePosition() + gravityOffset);
	}

	delete[] childSizes;
}

View* LinearPanel::Copy()
{
	LinearPanel* view = new LinearPanel();

	CopyBase(view);
	view->SetOrientation(orientation);

	return view;
}

Orientation LinearPanel::GetOrientation()
{
	return orientation;
}

void LinearPanel::SetOrientation(Orientation orientation)
{
	this->orientation = orientation;
}

bool LinearPanel::SetProperty(string name, string value)
{
	bool propertyHandled = View::SetProperty(name, value);

	if (propertyHandled)
		return true;

	if (name == "orientation")
	{
		if (value == "horizontal")
			SetOrientation(OrientationHorizontal);
		else if (value == "vertical")
			SetOrientation(OrientationVertical);
		else
			throw runtime_error("invalid orientation");

		return true;
	}

	return false;
}

Position LinearPanel::GetPositionForItemIndex(int elementNo)
{
	Position position = Position(-1, -1);

	if (elementNo < 0 || elementNo >= children.size())
		return position;

	if (orientation == OrientationHorizontal)
	{
		position.x = elementNo;
		position.y = 0;
	}
	else
	{
		position.x = 0;
		position.y = elementNo;
	}

	return position;
}

int LinearPanel::GetItemIndexForPosition(Position position)
{
	if (orientation == OrientationHorizontal)
	{
		if (position.x < 0 || position.x >= children.size())
			return -1;

		if (position.y != 0)
			return -1;

		return position.x;
	}
	else
	{
		if (position.x != 0)
			return -1;

		if (position.y < 0 || position.y >= children.size())
			return -1;

		return position.y;
	}
}

View* LinearPanel::GetSelectedItem()
{
	return children[selectedIndex];
}

View* LinearPanel::SelectNext(Direction direction)
{
	if (children.size() == 0)
		return NULL;

	int dx = 0;
	int dy = 0;

	switch (direction)
	{
	case DirectionUp:
		dy = -1;
		break;
	case DirectionDown:
		dy = 1;
		break;
	case DirectionLeft:
		dx = -1;
		break;
	case DirectionRight:
		dx = 1;
		break;
	}

	int index = selectedIndex;

	if (orientation == OrientationHorizontal)
	{
		if (selectedIndex + dx < 0 || selectedIndex + dx >= children.size())
			return NULL;

		if (dy != 0)
			return NULL;

		index += dx;
	}

	if (orientation == OrientationVertical)
	{
		if (dx != 0)
			return NULL;

		if (selectedIndex + dy < 0 || selectedIndex + dy >= children.size())
			return NULL;

		index += dy;
	}

	// A new selection was made
	SelectByIndex(index);

	return children[index];
}

View* LinearPanel::Select(Position position)
{
	PropagateStateChange("stateSelected", "false");

	int index = GetItemIndexForPosition(position);
	if (index >= 0 && index < children.size())
	{
		children[index]->PropagateStateChange("stateSelected", "true");
		ScrollTo(children[index]);
		return children[index];
	}
	else
	{
		return NULL;
	}
}

void LinearPanel::OnSelectionChanged()
{
	ScrollTo(children[selectedIndex]);
}
<|endoftext|>


<commit_before>/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
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 Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
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 Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "ExtractorCallbacks.h"
#include "ExtractionHelperFunctions.h"

ExtractorCallbacks::ExtractorCallbacks() {externalMemory = NULL; stringMap = NULL; }
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap) {
    externalMemory = ext;
    stringMap = strMap;
}

ExtractorCallbacks::~ExtractorCallbacks() {
}

/** warning: caller needs to take care of synchronization! */
bool ExtractorCallbacks::nodeFunction(_Node &n) {
    if(n.lat <= 85*100000 && n.lat >= -85*100000)
        externalMemory->allNodes.push_back(n);
    return true;
}

bool ExtractorCallbacks::restrictionFunction(_RawRestrictionContainer &r) {
    externalMemory->restrictionsVector.push_back(r);
    return true;
}

/** warning: caller needs to take care of synchronization! */
bool ExtractorCallbacks::wayFunction(_Way &w) {
    /*** Store name of way and split it into edge segments ***/

    if ( w.speed > 0 ) { //Only true if the way is specified by the speed profile

        //Get the unique identifier for the street name
        const StringMap::const_iterator strit = stringMap->find(w.name);
        if(strit == stringMap->end()) {
            w.nameID = externalMemory->nameVector.size();
            externalMemory->nameVector.push_back(w.name);
            stringMap->insert(StringMap::value_type(w.name, w.nameID));
        } else {
            w.nameID = strit->second;
        }

        if(fabs(-1. - w.speed) < FLT_EPSILON){
            WARN("found way with bogus speed, id: " << w.id);
            return true;
        }
        if(w.id == UINT_MAX) {
            WARN("found way with unknown type: " << w.id);
            return true;
        }

        if ( w.direction == _Way::opposite ){
            std::reverse( w.path.begin(), w.path.end() );
        }

        for(std::vector< NodeID >::size_type n = 0; n < w.path.size()-1; ++n) {
            externalMemory->allEdges.push_back(_Edge(w.path[n], w.path[n+1], w.type, w.direction, w.speed, w.nameID, w.roundabout, w.ignoreInGrid, w.isDurationSet, w.isAccessRestricted));
            externalMemory->usedNodeIDs.push_back(w.path[n]);
        }
        externalMemory->usedNodeIDs.push_back(w.path.back());

        //The following information is needed to identify start and end segments of restrictions
        externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(w.id, w.path[0], w.path[1], w.path[w.path.size()-2], w.path[w.path.size()-1]));
    }
    return true;
}
<commit_msg>Parsing duration when present<commit_after>/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
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 Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
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 Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "ExtractorCallbacks.h"
#include "ExtractionHelperFunctions.h"

ExtractorCallbacks::ExtractorCallbacks() {externalMemory = NULL; stringMap = NULL; }
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap) {
    externalMemory = ext;
    stringMap = strMap;
}

ExtractorCallbacks::~ExtractorCallbacks() {
}

/** warning: caller needs to take care of synchronization! */
bool ExtractorCallbacks::nodeFunction(_Node &n) {
    if(n.lat <= 85*100000 && n.lat >= -85*100000)
        externalMemory->allNodes.push_back(n);
    return true;
}

bool ExtractorCallbacks::restrictionFunction(_RawRestrictionContainer &r) {
    externalMemory->restrictionsVector.push_back(r);
    return true;
}

/** warning: caller needs to take care of synchronization! */
bool ExtractorCallbacks::wayFunction(_Way &w) {
    /*** Store name of way and split it into edge segments ***/

    if ( 0 < w.speed > 0 || 0 < w.duration ) { //Only true if the way is specified by the speed profile
        //Get the unique identifier for the street name
        const StringMap::const_iterator strit = stringMap->find(w.name);
        if(strit == stringMap->end()) {
            w.nameID = externalMemory->nameVector.size();
            externalMemory->nameVector.push_back(w.name);
            stringMap->insert(StringMap::value_type(w.name, w.nameID));
        } else {
            w.nameID = strit->second;
        }

        if(w.duration > 0) {
        	//TODO: iterate all way segments and set duration corresponding to the length of each segment
        	w.speed = w.duration/(w.path.size()-1);
        }

        if(fabs(-1. - w.speed) < FLT_EPSILON){
            WARN("found way with bogus speed, id: " << w.id);
            return true;
        }
        if(w.id == UINT_MAX) {
            WARN("found way with unknown type: " << w.id);
            return true;
        }

        if ( w.direction == _Way::opposite ){
            std::reverse( w.path.begin(), w.path.end() );
        }

        for(std::vector< NodeID >::size_type n = 0; n < w.path.size()-1; ++n) {
            externalMemory->allEdges.push_back(_Edge(w.path[n], w.path[n+1], w.type, w.direction, w.speed, w.nameID, w.roundabout, w.ignoreInGrid, (w.duration > 0), w.isAccessRestricted));
            externalMemory->usedNodeIDs.push_back(w.path[n]);
        }
        externalMemory->usedNodeIDs.push_back(w.path.back());

        //The following information is needed to identify start and end segments of restrictions
        externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(w.id, w.path[0], w.path[1], w.path[w.path.size()-2], w.path[w.path.size()-1]));
    }
    return true;
}
<|endoftext|>