<commit_before>#include "sshtunneloutconnection.h"
#include "sshtunnelout.h"
#include "sshclient.h"

Q_LOGGING_CATEGORY(logsshtunneloutconnection, "ssh.tunnelout.connection")
Q_LOGGING_CATEGORY(logsshtunneloutconnectiontransfer, "ssh.tunnelout.connection.transfer")

#define _DEBUG_ qCDebug(logsshtunneloutconnection) << m_name
#define _DEBUGT_ qCDebug(logsshtunneloutconnectiontransfer) << m_name

#define SOCKET_WRITE_ERROR (-1001)

SshTunnelOutConnection::SshTunnelOutConnection(const QString &name, SshClient *client, QTcpServer &server, quint16 remotePort)
    : SshChannel(name, client)
    , m_server(server)
    , m_port(remotePort)
    , m_tx_stop_ptr(m_tx_buffer)
{
    QObject::connect(this, &SshTunnelOutConnection::sendEvent, this, &SshTunnelOutConnection::_eventLoop, Qt::QueuedConnection);
    _DEBUG_ << "Create SshTunnelOutConnection (constructor)";
    emit sendEvent();
}

SshTunnelOutConnection::~SshTunnelOutConnection()
{
    _DEBUG_ << "Free SshTunnelOutConnection (destructor)";
}

void SshTunnelOutConnection::close()
{
    _DEBUG_ << "Close SshTunnelOutConnection asked";
    setChannelState(ChannelState::Close);
    emit sendEvent();
}

int SshTunnelOutConnection::_displaySshError(const QString &msg)
{
    char *emsg;
    int size;
    int ret = libssh2_session_last_error(m_sshClient->session(), &emsg, &size, 0);
    if(ret == LIBSSH2_ERROR_EAGAIN)
    {
        /* Process next connection */
        m_sshWaiting = true;
        return LIBSSH2_ERROR_EAGAIN;
    }
    qCCritical(logsshtunneloutconnection) << m_name << "Error" << ret << msg << QString(emsg);
    return ret;
}

ssize_t SshTunnelOutConnection::_transferSockToTx()
{
    qint64 len = 0;
    if(m_tx_stop_ptr != nullptr)
    {
        qCWarning(logsshtunneloutconnection) << m_name << "Asking transfer sock to tx when buffer not empty (" << m_tx_stop_ptr - m_tx_start_ptr << " bytes)";
        return -1;
    }

    if(m_sock == nullptr && m_sock->state() != QAbstractSocket::ConnectedState)
    {
        qCCritical(logsshtunneloutconnectiontransfer) << m_name << "_transferSockToTx on invalid socket";
        return -1;
    }

    len = m_sock->read(m_tx_buffer, BUFFER_SIZE);
    if(len > 0)
    {
        m_tx_stop_ptr = m_tx_buffer + len;
        m_tx_start_ptr = m_tx_buffer;
        if(len < BUFFER_SIZE)
        {
            m_data_to_tx = false;
        }
        _DEBUG_ << "_transferSockToTx: " << len << "bytes (available:" << m_sock->bytesAvailable() << ", state:" << m_sock->state() << ")";
        if(m_sock->state() == QAbstractSocket::UnconnectedState)
        {
            _DEBUG_ << "Detect Socket disconnected";
            m_tx_closed = true;
            emit sendEvent();
        }
    }
    else
    {
        m_tx_stop_ptr = nullptr;
        m_tx_start_ptr = nullptr;
        _DEBUG_ << "_transferSockToTx: error: " << len;
    }

    return len;
}

ssize_t SshTunnelOutConnection::_transferTxToSsh()
{
    ssize_t transfered = 0;

    while(m_tx_start_ptr < m_tx_stop_ptr)
    {
        ssize_t len = libssh2_channel_write(m_sshChannel, m_tx_start_ptr, m_tx_stop_ptr - m_tx_start_ptr);
        if(len == LIBSSH2_ERROR_EAGAIN)
        {
            _DEBUG_ << "_transferTxToSsh: write again" ;
            return 0;
        }
        if (len < 0)
        {
            _DEBUG_ << "_transferTxToSsh: write again" ;
            return _displaySshError("libssh2_channel_write");
        }
        if (len == 0)
        {
            qCWarning(logsshtunneloutconnectiontransfer) << m_name << "ERROR:  libssh2_channel_write return 0";
            return 0;
        }
        /* xfer OK */
        m_tx_start_ptr += len;
        transfered += len;
        _DEBUG_ << "_transferTxToSsh: write on SSH return " << len << "bytes" ;

        if(m_tx_start_ptr == m_tx_stop_ptr)
        {
            _DEBUG_ << "_transferTxToSsh: All buffer sent on SSH, buffer empty" ;
            m_tx_stop_ptr = nullptr;
            m_tx_start_ptr = nullptr;
        }
    }
    return transfered;
}

ssize_t SshTunnelOutConnection::_transferSshToRx()
{
    ssize_t sshread = 0;

    if(m_rx_stop_ptr != nullptr)
    {
        qCWarning(logsshtunneloutconnection) << "Buffer not empty, need to retry later";
        emit sendEvent();
        return 0;
    }

    sshread = static_cast<ssize_t>(libssh2_channel_read(m_sshChannel, m_rx_buffer, BUFFER_SIZE));
    if (sshread < 0)
    {
        if(sshread != LIBSSH2_ERROR_EAGAIN)
        {
            _DEBUG_ << "_transferSshToRx: " << sshread << " (error)";
            m_rx_stop_ptr = nullptr;
            _displaySshError(QString("libssh2_channel_read (%1 / %2)").arg(sshread).arg(BUFFER_SIZE));
        }
        else
        {
            _DEBUG_ << "_transferSshToRx: LIBSSH2_ERROR_EAGAIN";
            m_data_to_rx = false;
        }
        return sshread;
    }

    if(sshread < BUFFER_SIZE)
    {
        _DEBUG_ << "_transferSshToRx: Xfer " << sshread << "bytes";
        m_data_to_rx = false;
        if (libssh2_channel_eof(m_sshChannel))
        {
            m_rx_closed = true;
            _DEBUG_ << "_transferSshToRx: Ssh channel closed";
        }
    }
    else
    {
        _DEBUG_ << "_transferSshToRx: Xfer " << sshread << "bytes; There is probably more data to read, re-arm event";
        emit sendEvent();
    }
    m_rx_stop_ptr = m_rx_buffer + sshread;
    m_rx_start_ptr = m_rx_buffer;
    return sshread;
}

ssize_t SshTunnelOutConnection::_transferRxToSock()
{
    ssize_t total = 0;

    /* If socket not ready, wait for socket connected */
    if(!m_sock || m_sock->state() != QAbstractSocket::ConnectedState)
    {
        qCWarning(logsshtunneloutconnection) << m_name << "_transferRxToSock: Data on SSH when socket closed";
        m_dataWaitingOnSsh = true;
        return -1;
    }

    if(m_rx_stop_ptr == nullptr)
    {
        qCWarning(logsshtunneloutconnection) <<  m_name << "Buffer empty";
        return 0;
    }

    _DEBUG_ << "_transferRxToSock: libssh2_channel_read return " << (m_rx_stop_ptr - m_rx_start_ptr) << "bytes";

    while (m_rx_start_ptr < m_rx_stop_ptr)
    {
        ssize_t slen = m_sock->write(m_rx_start_ptr, m_rx_stop_ptr - m_rx_start_ptr);
        if (slen <= 0)
        {
            qCWarning(logsshtunneloutconnectiontransfer) << "ERROR : " << m_name << " local failed to write (" << slen << ")";
            return slen;
        }
        m_rx_start_ptr += slen;
        total += slen;
        _DEBUG_ << "_transferRxToSock: " << slen << "bytes written on socket";
    }

    /* Buffer is empty */
    m_rx_stop_ptr = nullptr;
    m_rx_start_ptr = nullptr;
    return total;
}

void SshTunnelOutConnection::_socketStateChanged(QAbstractSocket::SocketState socketState)
{
    _DEBUG_ << "_socketStateChanged: Socket State changed: " << socketState;
}

void SshTunnelOutConnection::_socketDisconnected()
{
    _DEBUG_ << "_socketDisconnected: Socket disconnected";
    m_tx_closed = true;
    emit sendEvent();
}

void SshTunnelOutConnection::_socketDataRecived()
{
    _DEBUG_ << "_socketDataRecived: Socket data received";
    m_data_to_tx = true;
    emit sendEvent();
}

void SshTunnelOutConnection::sshDataReceived()
{
    _DEBUG_ << "sshDataReceived: SSH data received";
    m_data_to_rx = true;
    emit sendEvent();
}

void SshTunnelOutConnection::_socketError()
{
    _DEBUG_ << "_socketError";
    auto error = m_sock->error();
    switch(error)
    {
        case QAbstractSocket::RemoteHostClosedError:
            _DEBUG_ << "socket RemoteHostClosedError";
            // Socket will be closed just after this, nothing to care about
            break;
        default:
            qCWarning(logsshtunneloutconnection) << m_name << "socket error=" << error << m_sock->errorString();
            // setChannelState(ChannelState::Close);
    }
}

void SshTunnelOutConnection::_eventLoop()
{
    switch(channelState())
    {
        case Openning:
        {
            if ( ! m_sshClient->takeChannelCreationMutex(this) )
            {
                return;
            }
            m_sshChannel = libssh2_channel_direct_tcpip(m_sshClient->session(),  "127.0.0.1", m_port);
            m_sshClient->releaseChannelCreationMutex(this);
            if (m_sshChannel == nullptr)
            {
                char *emsg;
                int size;
                int ret = libssh2_session_last_error(m_sshClient->session(), &emsg, &size, 0);
                if(ret == LIBSSH2_ERROR_EAGAIN)
                {
                    return;
                }
                if(!m_error)
                {
                    qCDebug(logsshtunneloutconnection) << "Refuse client socket connection on " << m_server.serverPort() << QString(emsg);
                    m_error = true;
                    m_sock = m_server.nextPendingConnection();
                    if(m_sock)
                    {
                        m_sock->close();
                        m_sock->deleteLater();
                    }
                    m_server.close();
                }
                setChannelState(ChannelState::Error);
                qCWarning(logsshtunneloutconnection) << "Channel session open failed";
                return;
            }
            _DEBUG_ << "Channel session opened";
            setChannelState(ChannelState::Exec);
        }

        FALLTHROUGH; case Exec:
        {
            m_sock = m_server.nextPendingConnection();
            if(!m_sock)
            {
                m_server.close();
                setChannelState(ChannelState::Error);
                qCWarning(logsshtunneloutconnection) << "Fail to get client socket";
                setChannelState(ChannelState::Close);
                return;
            }

            QObject::connect(m_sock, &QTcpSocket::stateChanged,
                             this,   &SshTunnelOutConnection::_socketStateChanged);

            QObject::connect(m_sock, &QTcpSocket::readyRead,
                             this,   &SshTunnelOutConnection::_socketDataRecived);

            QObject::connect(m_sock, &QTcpSocket::disconnected,
                             this,   &SshTunnelOutConnection::_socketDisconnected);

            QObject::connect(m_sock, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
                             this,   &SshTunnelOutConnection::_socketError);

            m_name = QString(m_name + ":%1").arg(m_sock->localPort());
            _DEBUG_ << "createConnection: " << m_sock << m_sock->localPort();
            m_rx_start_ptr = nullptr;
            m_rx_stop_ptr = nullptr;
            m_tx_start_ptr = nullptr;
            m_tx_stop_ptr = nullptr;
            m_data_to_tx = true;
            setChannelState(ChannelState::Read);
            /* OK, next step */
        }

        FALLTHROUGH; case Read:
        {
            _DEBUG_ << "_eventLoop in" << channelState() << "RX:" << m_data_to_rx << " TX:" << m_data_to_tx << " BUFTX:" << m_tx_start_ptr << " BUFRX:" << m_rx_start_ptr;
            ssize_t xfer = 0;
            if(m_rx_start_ptr) xfer += _transferRxToSock();
            if(m_data_to_rx)   _transferSshToRx();
            if(m_rx_start_ptr) xfer += _transferRxToSock();

            if(m_tx_start_ptr) xfer += _transferTxToSsh();
            if(m_data_to_tx)   _transferSockToTx();
            if(m_tx_start_ptr) xfer += _transferTxToSsh();

            if(m_tx_closed && (m_tx_start_ptr == nullptr))
            {
                _DEBUG_ << "Send EOF to SSH";
                libssh2_channel_send_eof(m_sshChannel);
                setChannelState(ChannelState::Close);
            }

            _DEBUG_ << "_eventLoop out:" << channelState() << "RX:" << m_data_to_rx << " TX:" << m_data_to_tx << " BUFTX:" << m_tx_start_ptr << " BUFRX:" << m_rx_start_ptr;
            return;
        }

        case Close:
        {
            if(!m_disconnectedFromSock && m_sock && m_sock->state() == QAbstractSocket::ConnectedState)
            {
                m_sock->disconnectFromHost();
            }
            _DEBUG_ << "closeChannel";
            setChannelState(ChannelState::WaitClose);
        }

        FALLTHROUGH; case WaitClose:
        {
            _DEBUG_ << "Wait close channel";
            if(m_sock->state() == QAbstractSocket::UnconnectedState)
            {
                setChannelState(ChannelState::Freeing);
            }
        }

        FALLTHROUGH; case Freeing:
        {
            _DEBUG_ << "free Channel";

            int ret = libssh2_channel_free(m_sshChannel);
            if(ret == LIBSSH2_ERROR_EAGAIN)
            {
                return;
            }
            if(ret < 0)
            {
                if(!m_error)
                {
                    m_error = true;
                    qCWarning(logsshtunneloutconnection) << "Failed to free channel: " << sshErrorToString(ret);
                }
            }
            if(m_error)
            {
                setChannelState(ChannelState::Error);
            }
            else
            {
                setChannelState(ChannelState::Free);
            }
            m_sshChannel = nullptr;
            QObject::disconnect(m_sshClient, &SshClient::sshDataReceived, this, &SshTunnelOutConnection::sshDataReceived);
            emit canBeDestroy(this);
            return;
        }

        case Free:
        {
            qCDebug(logsshtunneloutconnection) << "Channel" << m_name << "is free";
            return;
        }

        case Error:
        {
            qCDebug(logsshtunneloutconnection) << "Channel" << m_name << "is in error state";
            return;
        }
    }
}

<commit_msg>Fix test 1MB<commit_after>#include "sshtunneloutconnection.h"
#include "sshtunnelout.h"
#include "sshclient.h"

Q_LOGGING_CATEGORY(logsshtunneloutconnection, "ssh.tunnelout.connection")
Q_LOGGING_CATEGORY(logsshtunneloutconnectiontransfer, "ssh.tunnelout.connection.transfer")

#define _DEBUG_ qCDebug(logsshtunneloutconnection) << m_name
#define _DEBUGT_ qCDebug(logsshtunneloutconnectiontransfer) << m_name

#define SOCKET_WRITE_ERROR (-1001)

SshTunnelOutConnection::SshTunnelOutConnection(const QString &name, SshClient *client, QTcpServer &server, quint16 remotePort)
    : SshChannel(name, client)
    , m_server(server)
    , m_port(remotePort)
    , m_tx_stop_ptr(m_tx_buffer)
{
    QObject::connect(this, &SshTunnelOutConnection::sendEvent, this, &SshTunnelOutConnection::_eventLoop, Qt::QueuedConnection);
    _DEBUG_ << "Create SshTunnelOutConnection (constructor)";
    emit sendEvent();
}

SshTunnelOutConnection::~SshTunnelOutConnection()
{
    _DEBUG_ << "Free SshTunnelOutConnection (destructor)";
}

void SshTunnelOutConnection::close()
{
    _DEBUG_ << "Close SshTunnelOutConnection asked";
    setChannelState(ChannelState::Close);
    emit sendEvent();
}

int SshTunnelOutConnection::_displaySshError(const QString &msg)
{
    char *emsg;
    int size;
    int ret = libssh2_session_last_error(m_sshClient->session(), &emsg, &size, 0);
    if(ret == LIBSSH2_ERROR_EAGAIN)
    {
        /* Process next connection */
        m_sshWaiting = true;
        return LIBSSH2_ERROR_EAGAIN;
    }
    qCCritical(logsshtunneloutconnection) << m_name << "Error" << ret << msg << QString(emsg);
    return ret;
}

ssize_t SshTunnelOutConnection::_transferSockToTx()
{
    qint64 len = 0;
    if(m_tx_stop_ptr != nullptr)
    {
        qCWarning(logsshtunneloutconnection) << m_name << "Asking transfer sock to tx when buffer not empty (" << m_tx_stop_ptr - m_tx_start_ptr << " bytes)";
        return -1;
    }

    if(m_sock == nullptr && m_sock->state() != QAbstractSocket::ConnectedState)
    {
        qCCritical(logsshtunneloutconnectiontransfer) << m_name << "_transferSockToTx on invalid socket";
        return -1;
    }

    len = m_sock->read(m_tx_buffer, BUFFER_SIZE);
    if(len > 0)
    {
        m_tx_stop_ptr = m_tx_buffer + len;
        m_tx_start_ptr = m_tx_buffer;
        if(len < BUFFER_SIZE)
        {
            m_data_to_tx = false;
        }
        _DEBUG_ << "_transferSockToTx: " << len << "bytes (available:" << m_sock->bytesAvailable() << ", state:" << m_sock->state() << ")";
        if(m_sock->bytesAvailable() == 0)
        {
            if(m_sock->state() == QAbstractSocket::UnconnectedState)
            {
                _DEBUG_ << "Detect Socket disconnected";
                m_tx_closed = true;
                emit sendEvent();
            }
        }
        else
        {
            m_data_to_tx = true;
            _DEBUG_ << "_transferSockToTx: There is other data in socket, re-arm read";
            emit sendEvent();
        }
    }
    else
    {
        m_tx_stop_ptr = nullptr;
        m_tx_start_ptr = nullptr;
        _DEBUG_ << "_transferSockToTx: error: " << len;
    }

    return len;
}

ssize_t SshTunnelOutConnection::_transferTxToSsh()
{
    ssize_t transfered = 0;

    while(m_tx_start_ptr < m_tx_stop_ptr)
    {
        ssize_t len = libssh2_channel_write(m_sshChannel, m_tx_start_ptr, m_tx_stop_ptr - m_tx_start_ptr);
        if(len == LIBSSH2_ERROR_EAGAIN)
        {
            _DEBUG_ << "_transferTxToSsh: write again" ;
            return 0;
        }
        if (len < 0)
        {
            _DEBUG_ << "_transferTxToSsh: write again" ;
            return _displaySshError("libssh2_channel_write");
        }
        if (len == 0)
        {
            qCWarning(logsshtunneloutconnectiontransfer) << m_name << "ERROR:  libssh2_channel_write return 0";
            return 0;
        }
        /* xfer OK */
        m_tx_start_ptr += len;
        transfered += len;
        _DEBUG_ << "_transferTxToSsh: write on SSH return " << len << "bytes" ;

        if(m_tx_start_ptr == m_tx_stop_ptr)
        {
            _DEBUG_ << "_transferTxToSsh: All buffer sent on SSH, buffer empty" ;
            m_tx_stop_ptr = nullptr;
            m_tx_start_ptr = nullptr;
        }
    }
    return transfered;
}

ssize_t SshTunnelOutConnection::_transferSshToRx()
{
    ssize_t sshread = 0;

    if(m_rx_stop_ptr != nullptr)
    {
        qCWarning(logsshtunneloutconnection) << "Buffer not empty, need to retry later";
        emit sendEvent();
        return 0;
    }

    sshread = static_cast<ssize_t>(libssh2_channel_read(m_sshChannel, m_rx_buffer, BUFFER_SIZE));
    if (sshread < 0)
    {
        if(sshread != LIBSSH2_ERROR_EAGAIN)
        {
            _DEBUG_ << "_transferSshToRx: " << sshread << " (error)";
            m_rx_stop_ptr = nullptr;
            _displaySshError(QString("libssh2_channel_read (%1 / %2)").arg(sshread).arg(BUFFER_SIZE));
        }
        else
        {
            _DEBUG_ << "_transferSshToRx: LIBSSH2_ERROR_EAGAIN";
            m_data_to_rx = false;
        }
        return sshread;
    }

    if(sshread < BUFFER_SIZE)
    {
        _DEBUG_ << "_transferSshToRx: Xfer " << sshread << "bytes";
        m_data_to_rx = false;
        if (libssh2_channel_eof(m_sshChannel))
        {
            m_rx_closed = true;
            _DEBUG_ << "_transferSshToRx: Ssh channel closed";
        }
    }
    else
    {
        _DEBUG_ << "_transferSshToRx: Xfer " << sshread << "bytes; There is probably more data to read, re-arm event";
        emit sendEvent();
    }
    m_rx_stop_ptr = m_rx_buffer + sshread;
    m_rx_start_ptr = m_rx_buffer;
    return sshread;
}

ssize_t SshTunnelOutConnection::_transferRxToSock()
{
    ssize_t total = 0;

    /* If socket not ready, wait for socket connected */
    if(!m_sock || m_sock->state() != QAbstractSocket::ConnectedState)
    {
        qCWarning(logsshtunneloutconnection) << m_name << "_transferRxToSock: Data on SSH when socket closed";
        m_dataWaitingOnSsh = true;
        return -1;
    }

    if(m_rx_stop_ptr == nullptr)
    {
        qCWarning(logsshtunneloutconnection) <<  m_name << "Buffer empty";
        return 0;
    }

    _DEBUG_ << "_transferRxToSock: libssh2_channel_read return " << (m_rx_stop_ptr - m_rx_start_ptr) << "bytes";

    while (m_rx_start_ptr < m_rx_stop_ptr)
    {
        ssize_t slen = m_sock->write(m_rx_start_ptr, m_rx_stop_ptr - m_rx_start_ptr);
        if (slen <= 0)
        {
            qCWarning(logsshtunneloutconnectiontransfer) << "ERROR : " << m_name << " local failed to write (" << slen << ")";
            return slen;
        }
        m_rx_start_ptr += slen;
        total += slen;
        _DEBUG_ << "_transferRxToSock: " << slen << "bytes written on socket";
    }

    /* Buffer is empty */
    m_rx_stop_ptr = nullptr;
    m_rx_start_ptr = nullptr;
    return total;
}

void SshTunnelOutConnection::_socketStateChanged(QAbstractSocket::SocketState socketState)
{
    _DEBUG_ << "_socketStateChanged: Socket State changed: " << socketState;
}

void SshTunnelOutConnection::_socketDisconnected()
{
    _DEBUG_ << "_socketDisconnected: Socket disconnected";
    m_tx_closed = true;
    emit sendEvent();
}

void SshTunnelOutConnection::_socketDataRecived()
{
    _DEBUG_ << "_socketDataRecived: Socket data received";
    m_data_to_tx = true;
    emit sendEvent();
}

void SshTunnelOutConnection::sshDataReceived()
{
    _DEBUG_ << "sshDataReceived: SSH data received";
    m_data_to_rx = true;
    emit sendEvent();
}

void SshTunnelOutConnection::_socketError()
{
    _DEBUG_ << "_socketError";
    auto error = m_sock->error();
    switch(error)
    {
        case QAbstractSocket::RemoteHostClosedError:
            _DEBUG_ << "socket RemoteHostClosedError";
            // Socket will be closed just after this, nothing to care about
            break;
        default:
            qCWarning(logsshtunneloutconnection) << m_name << "socket error=" << error << m_sock->errorString();
            // setChannelState(ChannelState::Close);
    }
}

void SshTunnelOutConnection::_eventLoop()
{
    switch(channelState())
    {
        case Openning:
        {
            if ( ! m_sshClient->takeChannelCreationMutex(this) )
            {
                return;
            }
            m_sshChannel = libssh2_channel_direct_tcpip(m_sshClient->session(),  "127.0.0.1", m_port);
            m_sshClient->releaseChannelCreationMutex(this);
            if (m_sshChannel == nullptr)
            {
                char *emsg;
                int size;
                int ret = libssh2_session_last_error(m_sshClient->session(), &emsg, &size, 0);
                if(ret == LIBSSH2_ERROR_EAGAIN)
                {
                    return;
                }
                if(!m_error)
                {
                    qCDebug(logsshtunneloutconnection) << "Refuse client socket connection on " << m_server.serverPort() << QString(emsg);
                    m_error = true;
                    m_sock = m_server.nextPendingConnection();
                    if(m_sock)
                    {
                        m_sock->close();
                        m_sock->deleteLater();
                    }
                    m_server.close();
                }
                setChannelState(ChannelState::Error);
                qCWarning(logsshtunneloutconnection) << "Channel session open failed";
                return;
            }
            _DEBUG_ << "Channel session opened";
            setChannelState(ChannelState::Exec);
        }

        FALLTHROUGH; case Exec:
        {
            m_sock = m_server.nextPendingConnection();
            if(!m_sock)
            {
                m_server.close();
                setChannelState(ChannelState::Error);
                qCWarning(logsshtunneloutconnection) << "Fail to get client socket";
                setChannelState(ChannelState::Close);
                return;
            }

            QObject::connect(m_sock, &QTcpSocket::stateChanged,
                             this,   &SshTunnelOutConnection::_socketStateChanged);

            QObject::connect(m_sock, &QTcpSocket::readyRead,
                             this,   &SshTunnelOutConnection::_socketDataRecived);

            QObject::connect(m_sock, &QTcpSocket::disconnected,
                             this,   &SshTunnelOutConnection::_socketDisconnected);

            QObject::connect(m_sock, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
                             this,   &SshTunnelOutConnection::_socketError);

            m_name = QString(m_name + ":%1").arg(m_sock->localPort());
            _DEBUG_ << "createConnection: " << m_sock << m_sock->localPort();
            m_rx_start_ptr = nullptr;
            m_rx_stop_ptr = nullptr;
            m_tx_start_ptr = nullptr;
            m_tx_stop_ptr = nullptr;
            m_data_to_tx = true;
            setChannelState(ChannelState::Read);
            /* OK, next step */
        }

        FALLTHROUGH; case Read:
        {
            _DEBUG_ << "_eventLoop in" << channelState() << "RX:" << m_data_to_rx << " TX:" << m_data_to_tx << " BUFTX:" << m_tx_start_ptr << " BUFRX:" << m_rx_start_ptr;
            ssize_t xfer = 0;
            if(m_rx_start_ptr) xfer += _transferRxToSock();
            if(m_data_to_rx)   _transferSshToRx();
            if(m_rx_start_ptr) xfer += _transferRxToSock();

            if(m_tx_start_ptr) xfer += _transferTxToSsh();
            if(m_data_to_tx)   _transferSockToTx();
            if(m_tx_start_ptr) xfer += _transferTxToSsh();

            if(m_tx_closed && (m_tx_start_ptr == nullptr))
            {
                _DEBUG_ << "Send EOF to SSH";
                libssh2_channel_send_eof(m_sshChannel);
                setChannelState(ChannelState::Close);
            }

            _DEBUG_ << "_eventLoop out:" << channelState() << "RX:" << m_data_to_rx << " TX:" << m_data_to_tx << " BUFTX:" << m_tx_start_ptr << " BUFRX:" << m_rx_start_ptr;
            return;
        }

        case Close:
        {
            if(!m_disconnectedFromSock && m_sock && m_sock->state() == QAbstractSocket::ConnectedState)
            {
                m_sock->disconnectFromHost();
            }
            _DEBUG_ << "closeChannel";
            setChannelState(ChannelState::WaitClose);
        }

        FALLTHROUGH; case WaitClose:
        {
            _DEBUG_ << "Wait close channel";
            if(m_sock->state() == QAbstractSocket::UnconnectedState)
            {
                setChannelState(ChannelState::Freeing);
            }
        }

        FALLTHROUGH; case Freeing:
        {
            _DEBUG_ << "free Channel";

            int ret = libssh2_channel_free(m_sshChannel);
            if(ret == LIBSSH2_ERROR_EAGAIN)
            {
                return;
            }
            if(ret < 0)
            {
                if(!m_error)
                {
                    m_error = true;
                    qCWarning(logsshtunneloutconnection) << "Failed to free channel: " << sshErrorToString(ret);
                }
            }
            if(m_error)
            {
                setChannelState(ChannelState::Error);
            }
            else
            {
                setChannelState(ChannelState::Free);
            }
            m_sshChannel = nullptr;
            QObject::disconnect(m_sshClient, &SshClient::sshDataReceived, this, &SshTunnelOutConnection::sshDataReceived);
            emit canBeDestroy(this);
            return;
        }

        case Free:
        {
            qCDebug(logsshtunneloutconnection) << "Channel" << m_name << "is free";
            return;
        }

        case Error:
        {
            qCDebug(logsshtunneloutconnection) << "Channel" << m_name << "is in error state";
            return;
        }
    }
}

<|endoftext|>


<commit_before>/* Copyright 2014 Open Source Robotics Foundation, 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.
 */

#ifndef RCLCPP_RCLCPP_CLIENT_HPP_
#define RCLCPP_RCLCPP_CLIENT_HPP_

#include <memory>

#include <ros_middleware_interface/functions.h>
#include <ros_middleware_interface/handles.h>

#include <rclcpp/macros.hpp>

namespace rclcpp
{

// Forward declaration for friend statement
namespace node {class Node;}

namespace client
{

template<typename ServiceT>
class Client
{
public:
  RCLCPP_MAKE_SHARED_DEFINITIONS(Client);

  Client(ros_middleware_interface::ClientHandle client_handle,
         std::string& service_name)
    : client_handle_(client_handle), service_name_(service_name)
  {}

  std::shared_ptr<typename ServiceT::Response>
  send_request(std::shared_ptr<typename ServiceT::Request> &req)
  {
    ::ros_middleware_interface::send_request(client_handle_, req.get());

    std::shared_ptr<typename ServiceT::Response> res = std::make_shared<typename ServiceT::Response>();
    ::ros_middleware_interface::receive_response(client_handle_, res.get());
    return res;
  }

private:
  ros_middleware_interface::ClientHandle client_handle_;
  std::string service_name_;

};

} /* namespace client */
} /* namespace rclcpp */

#endif /* RCLCPP_RCLCPP_CLIENT_HPP_ */
<commit_msg>Added support for timeouts<commit_after>/* Copyright 2014 Open Source Robotics Foundation, 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.
 */

#ifndef RCLCPP_RCLCPP_CLIENT_HPP_
#define RCLCPP_RCLCPP_CLIENT_HPP_

#include <memory>

#include <ros_middleware_interface/functions.h>
#include <ros_middleware_interface/handles.h>

#include <rclcpp/macros.hpp>

namespace rclcpp
{

// Forward declaration for friend statement
namespace node {class Node;}

namespace client
{

template<typename ServiceT>
class Client
{
public:
  RCLCPP_MAKE_SHARED_DEFINITIONS(Client);

  Client(ros_middleware_interface::ClientHandle client_handle,
         std::string& service_name)
    : client_handle_(client_handle), service_name_(service_name)
  {}

  std::shared_ptr<typename ServiceT::Response>
  send_request(std::shared_ptr<typename ServiceT::Request> &req, long timeout=10)
  {
    ::ros_middleware_interface::send_request(client_handle_, req.get());

    std::shared_ptr<typename ServiceT::Response> res = std::make_shared<typename ServiceT::Response>();
    bool received = ::ros_middleware_interface::receive_response(client_handle_, res.get(), timeout);
    if(!received)
    {
      // TODO: use custom exception
      throw std::runtime_error("Timed out while waiting for response");
    }
    return res;
  }

private:
  ros_middleware_interface::ClientHandle client_handle_;
  std::string service_name_;

};

} /* namespace client */
} /* namespace rclcpp */

#endif /* RCLCPP_RCLCPP_CLIENT_HPP_ */
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://users.dune-project.org/projects/dune-stuff/
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

// This one has to come first (includes the config.h)!
#include <dune/stuff/test/test_common.hh>

#include <tuple>

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/la/container.hh>
#include <dune/stuff/la/solver.hh>

// toggle output
//std::ostream& out = std::cout;
std::ostream& out = DSC_LOG.devnull();

using namespace Dune::Stuff;
using namespace Dune::Stuff::LA;

typedef testing::Types< std::tuple< Dune::DynamicMatrix< double >, Dune::DynamicVector< double >, Dune::DynamicVector< double > >
#if HAVE_EIGEN
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenRowMajorSparseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
#endif // HAVE_EIGEN
#if HAVE_DUNE_ISTL
                      , std::tuple< IstlRowMajorSparseMatrix< double >, IstlDenseVector< double >, IstlDenseVector< double > >
#endif
                      > MatrixVectorCombinations;

template< class MatrixVectorCombination >
struct SolverTest
  : public ::testing::Test
{
  typedef typename std::tuple_element< 0, MatrixVectorCombination >::type MatrixType;
  typedef typename std::tuple_element< 1, MatrixVectorCombination >::type RhsType;
  typedef typename std::tuple_element< 2, MatrixVectorCombination >::type SolutionType;

  typedef Solver< MatrixType > SolverType;

  static void produces_correct_results()
  {
    const size_t dim = 10;
    const MatrixType matrix = Container< MatrixType >::create(dim);
    const RhsType rhs = Container< RhsType >::create(dim);
    SolutionType solution = Container< SolutionType >::create(dim);
    solution.scal(0);

    // dynamic test
    const SolverType solver(matrix);
    solver.apply(rhs, solution);
    if (!solution.almost_equal(rhs))
      DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Wrong solution!");
    solution.scal(0);

    // static tests
    typedef typename SolverType::MatrixType M;
    std::vector< std::string > opts = SolverType::options();
    if (opts.size() == 0) DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Solver has no options!");
    for (auto opt : opts) {
      out << "solving with option '" << opt << "' and detailed options" << std::endl;
      Common::ConfigTree detailed_opts = SolverType::options(opt);
      detailed_opts.report(out, "  ");

      // dynamic tests
      solver.apply(rhs, solution, opt);
      if (!solution.almost_equal(rhs))
        DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Wrong solution!");
      solution.scal(0);

      solver.apply(rhs, solution, detailed_opts);
      if (!solution.almost_equal(rhs))
        DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Wrong solution!");
      solution.scal(0);
    }
  } // ... produces_correct_results(...)
}; // struct SolverTest

TYPED_TEST_CASE(SolverTest, MatrixVectorCombinations);
TYPED_TEST(SolverTest, behaves_correctly) {
  this->produces_correct_results();
}

int main(int argc, char** argv)
{
  try {
    test_init(argc, argv);
    return RUN_ALL_TESTS();
  } catch (Dune::Exception& e) {
    std::cerr << e.what() << std::endl;
    std::abort();
  } catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
    std::abort();
  } catch (...) {
    std::cerr << "Unknown exception thrown!" << std::endl;
    std::abort();
  } // try
}
<commit_msg>[test.la_solver] update<commit_after>// This file is part of the dune-stuff project:
//   https://users.dune-project.org/projects/dune-stuff/
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

// This one has to come first (includes the config.h)!
#include <dune/stuff/test/test_common.hh>

#include <tuple>

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/la/container.hh>
#include <dune/stuff/la/solver.hh>

#include "la_container.hh"

// toggle output
//std::ostream& out = std::cout;
std::ostream& out = DSC_LOG.devnull();

using namespace Dune::Stuff;
using namespace Dune::Stuff::LA;

typedef testing::Types< std::tuple< CommonDenseMatrix< double >, CommonDenseVector< double >, CommonDenseVector< double > >
#if HAVE_EIGEN
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenRowMajorSparseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
#endif // HAVE_EIGEN
#if HAVE_DUNE_ISTL
                      , std::tuple< IstlRowMajorSparseMatrix< double >, IstlDenseVector< double >, IstlDenseVector< double > >
#endif
                      > MatrixVectorCombinations;

template< class MatrixVectorCombination >
struct SolverTest
  : public ::testing::Test
{
  typedef typename std::tuple_element< 0, MatrixVectorCombination >::type MatrixType;
  typedef typename std::tuple_element< 1, MatrixVectorCombination >::type RhsType;
  typedef typename std::tuple_element< 2, MatrixVectorCombination >::type SolutionType;

  typedef Solver< MatrixType > SolverType;

  static void produces_correct_results()
  {
    const size_t dim = 10;
    const MatrixType matrix = ContainerFactory< MatrixType >::create(dim);
    const RhsType rhs = ContainerFactory< RhsType >::create(dim);
    SolutionType solution = ContainerFactory< SolutionType >::create(dim);
    solution.scal(0);

    // dynamic test
    const SolverType solver(matrix);
    solver.apply(rhs, solution);
    if (!solution.almost_equal(rhs))
      DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Wrong solution!");
    solution.scal(0);

    // static tests
    typedef typename SolverType::MatrixType M;
    std::vector< std::string > opts = SolverType::options();
    if (opts.size() == 0) DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Solver has no options!");
    for (auto opt : opts) {
      out << "solving with option '" << opt << "' and detailed options" << std::endl;
      Common::ConfigTree detailed_opts = SolverType::options(opt);
      detailed_opts.report(out, "  ");

      // dynamic tests
      solver.apply(rhs, solution, opt);
      if (!solution.almost_equal(rhs))
        DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Wrong solution!");
      solution.scal(0);

      solver.apply(rhs, solution, detailed_opts);
      if (!solution.almost_equal(rhs))
        DUNE_THROW_COLORFULLY(Exceptions::results_are_not_as_expected, "Wrong solution!");
    }
  } // ... produces_correct_results(...)
}; // struct SolverTest

TYPED_TEST_CASE(SolverTest, MatrixVectorCombinations);
TYPED_TEST(SolverTest, behaves_correctly) {
  this->produces_correct_results();
}

int main(int argc, char** argv)
{
  try {
    test_init(argc, argv);
    return RUN_ALL_TESTS();
  } catch (Dune::Exception& e) {
    std::cerr << e.what() << std::endl;
    std::abort();
  } catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
    std::abort();
  } catch (...) {
    std::cerr << "Unknown exception thrown!" << std::endl;
    std::abort();
  } // try
}
<|endoftext|>


<commit_before>// Catch
#include <catch.hpp>

// C++ Standard Library
#include <memory>
#include <iostream>
#include <cmath>

// Boost
#include <boost/filesystem.hpp>

// Armadillo
#include <armadillo>

// HOP
#include <hop>

extern boost::filesystem::path testDirectory;
static std::string dataPath_ = "/data/optimisationAlgorithm/trajectoryBasedAlgrorithm/hillClimbing/";

class TestHillClimbing : public hop::HillClimbing {
  public:
    TestHillClimbing(
        const std::shared_ptr<hop::OptimisationProblem> optimisationProblem)
      : HillClimbing(optimisationProblem),
        velocityIndex_(0){
    }

    arma::Col<double> getVelocity() override {
      return velocities_.col(velocityIndex_++);
    }

    void setVelocitys(arma::mat velocities){
      velocities_ = velocities;
    }

  protected:
    unsigned int velocityIndex_;
    arma::mat velocities_;
};

class TestHillClimbingProblem : public hop::OptimisationProblem {
  public:
    TestHillClimbingProblem(
        const unsigned int numberOfDimensions)
      : OptimisationProblem(numberOfDimensions) {
      softConstraintsValuesIndex_ = 0;
      objectiveValuesIndex_ = 0;
      parameterHistory_.clear();
    }

    std::vector<arma::Col<double>> getParameterHistory() const noexcept {
      return parameterHistory_;
    }

    void setObjectiveValues(arma::Col<double> objectiveValues){
      objectiveValues_ = objectiveValues;
    }

    void setSoftConstraintsValues(arma::Col<double> softConstraintsValues){
      softConstraintsValues_ = softConstraintsValues;
    }

  protected:
    static unsigned int softConstraintsValuesIndex_;
    static unsigned int objectiveValuesIndex_;
    arma::Col<double> objectiveValues_;
    arma::Col<double> softConstraintsValues_;

    static std::vector<arma::Col<double>> parameterHistory_;

    double getSoftConstraintsValueImplementation(
       const arma::Col<double>& parameter) const override {

      return softConstraintsValues_.at(softConstraintsValuesIndex_++);
    }

    double getObjectiveValueImplementation(
       const arma::Col<double>& parameter) const override {
       parameterHistory_.push_back(parameter);

      return objectiveValues_.at(objectiveValuesIndex_++);
    }

    std::string to_string() const noexcept {
      return "TestHillClimbing";
    }
};

decltype(TestHillClimbingProblem::parameterHistory_) TestHillClimbingProblem::parameterHistory_;
decltype(TestHillClimbingProblem::softConstraintsValuesIndex_) TestHillClimbingProblem::softConstraintsValuesIndex_;
decltype(TestHillClimbingProblem::objectiveValuesIndex_) TestHillClimbingProblem::objectiveValuesIndex_;

TEST_CASE("Hill climbing", "") {

   // Set OptimisationProblem values
   arma::Col<double> upperBounds;
   upperBounds.load(testDirectory.string() + dataPath_ + "upperBounds.mat"); //the parametre is optional

   arma::Col<double> lowerBounds;
   lowerBounds.load(testDirectory.string() + dataPath_ + "lowerBounds.mat"); //the parametre is optional

   arma::Col<double> objectiveValues;
   objectiveValues.load(testDirectory.string() + dataPath_ + "objectiveValues[2.0].mat");

   arma::Col<double> softConstraintsValues;
   softConstraintsValues.load(testDirectory.string() + dataPath_ + "softConstraintsValues[2.0].mat");

   // Init OptimisationProblem
   std::shared_ptr<TestHillClimbingProblem> testHillClimbingProblem(new TestHillClimbingProblem(upperBounds.n_elem));
   testHillClimbingProblem->setUpperBounds(upperBounds);
   testHillClimbingProblem->setLowerBounds(lowerBounds);
   testHillClimbingProblem->setAcceptableObjectiveValue(-500.0);
   testHillClimbingProblem->setObjectiveValues(objectiveValues);
   testHillClimbingProblem->setSoftConstraintsValues(softConstraintsValues);

   // Set OptimisationAlgorithm values
   arma::mat velocities;
   velocities.load(testDirectory.string() + dataPath_ + "velocities[2.0].mat");

   arma::Col<double> initialParameter;
   initialParameter.load(testDirectory.string() + dataPath_ + "initialParameter[null].mat"); //the parametre is optional

   arma::Col<double> maximalStepSize;
   maximalStepSize.load(testDirectory.string() + dataPath_ + "maximalStepSize[2.1].mat"); //the parametre is optional

   // Init OptimisationAlgorithm
   TestHillClimbing testHillClimbing(testHillClimbingProblem);
   testHillClimbing.setVelocitys(velocities);
   testHillClimbing.setInitialParameter(initialParameter);
   testHillClimbing.setMaximalStepSize(maximalStepSize);

   // Set Expected values
   arma::Mat<double> expectedParameterHistory;
   expectedParameterHistory.load(testDirectory.string() + dataPath_ + "expected[2.1].mat");

   // Run hill climbing algorithm
  testHillClimbing.optimise();
  // Comparing of candidateParameters
  std::vector<arma::Col<double>> actualParameterHistory = testHillClimbingProblem->getParameterHistory();

  for(std::size_t n = 0; n < expectedParameterHistory.n_cols; ++n) {
    arma::Col<double> expectedParameter = expectedParameterHistory.col(n);
    arma::Col<double> actualParameter = actualParameterHistory.at(n);

    for (std::size_t k = 0; k < expectedParameter.n_elem; ++k) {
        if(isfinite(expectedParameter.at(k))) {
          CHECK(actualParameter.at(k) == Approx(expectedParameter.at(k)));
        } elese {
          CHECK(actualParameter.at(k) == expectedParameter.at(k));
        }
    }
  }
}

TEST_CASE("Hill climbing (init Test)", "") {

   // Set OptimisationProblem values
   arma::Col<double> upperBounds;
   upperBounds.load(testDirectory.string() + dataPath_ + "upperBounds.mat"); //the parametre is optional

   arma::Col<double> lowerBounds;
   lowerBounds.load(testDirectory.string() + dataPath_ + "lowerBounds.mat"); //the parametre is optional

   arma::Col<double> objectiveValues;
   objectiveValues.load(testDirectory.string() + dataPath_ + "objectiveValues[1.0].mat");

   arma::Col<double> softConstraintsValues;
   softConstraintsValues.load(testDirectory.string() + dataPath_ + "softConstraintsValues[1.0].mat");

   // Init OptimisationProblem
   std::shared_ptr<TestHillClimbingProblem> testHillClimbingProblem(new TestHillClimbingProblem(upperBounds.n_elem));
   testHillClimbingProblem->setUpperBounds(upperBounds);
   testHillClimbingProblem->setLowerBounds(lowerBounds);
   testHillClimbingProblem->setObjectiveValues(objectiveValues);
   testHillClimbingProblem->setSoftConstraintsValues(softConstraintsValues);
   testHillClimbingProblem->setAcceptableObjectiveValue(10.0);

   // Set OptimisationAlgorithm values
   arma::mat velocities;
   velocities.load(testDirectory.string() + dataPath_ + "velocities[1.0].mat");

   // Init OptimisationAlgorithm
   TestHillClimbing testHillClimbing(testHillClimbingProblem);
   testHillClimbing.setVelocitys(velocities);

   arma::Mat<double> expectedParameterHistory;

  SECTION("Check MaximalStepSize"){
    arma::Col<double> initialParameter;
    initialParameter.load(testDirectory.string() + dataPath_ + "initialParameter[null].mat"); //the parametre is optional

    expectedParameterHistory.load(testDirectory.string() + dataPath_ + "expected[1.1].mat");

    testHillClimbing.setInitialParameter(initialParameter);
    testHillClimbing.optimise();

    // Comparing of candidateParameters
    std::vector<arma::Col<double>> actualParameterHistory = testHillClimbingProblem->getParameterHistory();

    for(std::size_t n = 0; n < expectedParameterHistory.n_cols; ++n) {
      arma::Col<double> expectedParameter = expectedParameterHistory.col(n);
      arma::Col<double> actualParameter = actualParameterHistory.at(n);
      std::cout<<actualParameter;
      for (std::size_t k = 0; k < expectedParameter.n_elem; ++k) {
        if(isfinite(expectedParameter.at(k))) {
          CHECK(actualParameter.at(k) == Approx(expectedParameter.at(k)));
        } elese {
          CHECK(actualParameter.at(k) == expectedParameter.at(k));
        }
      }
    }

  }
/*
  SECTION("Check initialParameter at each limit "){
    arma::Col<double> initialParameter;
    initialParameter.load(testDirectory.string() + dataPath_ + "initialParameter[1.2].mat"); //the parametre is optional

    expectedParameterHistory.load(testDirectory.string() + dataPath_ + "expected[1.2].mat");

    testHillClimbing.setInitialParameter(initialParameter);
    testHillClimbing.optimise();

    // Comparing of candidateParameters
    std::vector<arma::Col<double>> actualParameterHistory = testHillClimbingProblem->getParameterHistory();

    for(std::size_t n = 0; n < expectedParameterHistory.n_cols; ++n) {
      arma::Col<double> expectedParameter = expectedParameterHistory.col(n);
      arma::Col<double> actualParameter = actualParameterHistory.at(n);

      for (std::size_t k = 0; k < expectedParameter.n_elem; ++k) {
        if(isfinite(expectedParameter.at(k))) {
          CHECK(actualParameter.at(k) == Approx(expectedParameter.at(k)));
        } elese {
          CHECK(actualParameter.at(k) == expectedParameter.at(k));
        }
      }
    }

  }
*/
}
<commit_msg>fix: Simple spelling error<commit_after>// Catch
#include <catch.hpp>

// C++ Standard Library
#include <memory>
#include <iostream>
#include <cmath>

// Boost
#include <boost/filesystem.hpp>

// Armadillo
#include <armadillo>

// HOP
#include <hop>

extern boost::filesystem::path testDirectory;
static std::string dataPath_ = "/data/optimisationAlgorithm/trajectoryBasedAlgrorithm/hillClimbing/";

class TestHillClimbing : public hop::HillClimbing {
  public:
    TestHillClimbing(
        const std::shared_ptr<hop::OptimisationProblem> optimisationProblem)
      : HillClimbing(optimisationProblem),
        velocityIndex_(0){
    }

    arma::Col<double> getVelocity() override {
      return velocities_.col(velocityIndex_++);
    }

    void setVelocitys(arma::mat velocities){
      velocities_ = velocities;
    }

  protected:
    unsigned int velocityIndex_;
    arma::mat velocities_;
};

class TestHillClimbingProblem : public hop::OptimisationProblem {
  public:
    TestHillClimbingProblem(
        const unsigned int numberOfDimensions)
      : OptimisationProblem(numberOfDimensions) {
      softConstraintsValuesIndex_ = 0;
      objectiveValuesIndex_ = 0;
      parameterHistory_.clear();
    }

    std::vector<arma::Col<double>> getParameterHistory() const noexcept {
      return parameterHistory_;
    }

    void setObjectiveValues(arma::Col<double> objectiveValues){
      objectiveValues_ = objectiveValues;
    }

    void setSoftConstraintsValues(arma::Col<double> softConstraintsValues){
      softConstraintsValues_ = softConstraintsValues;
    }

  protected:
    static unsigned int softConstraintsValuesIndex_;
    static unsigned int objectiveValuesIndex_;
    arma::Col<double> objectiveValues_;
    arma::Col<double> softConstraintsValues_;

    static std::vector<arma::Col<double>> parameterHistory_;

    double getSoftConstraintsValueImplementation(
       const arma::Col<double>& parameter) const override {

      return softConstraintsValues_.at(softConstraintsValuesIndex_++);
    }

    double getObjectiveValueImplementation(
       const arma::Col<double>& parameter) const override {
       parameterHistory_.push_back(parameter);

      return objectiveValues_.at(objectiveValuesIndex_++);
    }

    std::string to_string() const noexcept {
      return "TestHillClimbing";
    }
};

decltype(TestHillClimbingProblem::parameterHistory_) TestHillClimbingProblem::parameterHistory_;
decltype(TestHillClimbingProblem::softConstraintsValuesIndex_) TestHillClimbingProblem::softConstraintsValuesIndex_;
decltype(TestHillClimbingProblem::objectiveValuesIndex_) TestHillClimbingProblem::objectiveValuesIndex_;

TEST_CASE("Hill climbing", "") {

   // Set OptimisationProblem values
   arma::Col<double> upperBounds;
   upperBounds.load(testDirectory.string() + dataPath_ + "upperBounds.mat"); //the parametre is optional

   arma::Col<double> lowerBounds;
   lowerBounds.load(testDirectory.string() + dataPath_ + "lowerBounds.mat"); //the parametre is optional

   arma::Col<double> objectiveValues;
   objectiveValues.load(testDirectory.string() + dataPath_ + "objectiveValues[2.0].mat");

   arma::Col<double> softConstraintsValues;
   softConstraintsValues.load(testDirectory.string() + dataPath_ + "softConstraintsValues[2.0].mat");

   // Init OptimisationProblem
   std::shared_ptr<TestHillClimbingProblem> testHillClimbingProblem(new TestHillClimbingProblem(upperBounds.n_elem));
   testHillClimbingProblem->setUpperBounds(upperBounds);
   testHillClimbingProblem->setLowerBounds(lowerBounds);
   testHillClimbingProblem->setAcceptableObjectiveValue(-500.0);
   testHillClimbingProblem->setObjectiveValues(objectiveValues);
   testHillClimbingProblem->setSoftConstraintsValues(softConstraintsValues);

   // Set OptimisationAlgorithm values
   arma::mat velocities;
   velocities.load(testDirectory.string() + dataPath_ + "velocities[2.0].mat");

   arma::Col<double> initialParameter;
   initialParameter.load(testDirectory.string() + dataPath_ + "initialParameter[null].mat"); //the parametre is optional

   arma::Col<double> maximalStepSize;
   maximalStepSize.load(testDirectory.string() + dataPath_ + "maximalStepSize[2.1].mat"); //the parametre is optional

   // Init OptimisationAlgorithm
   TestHillClimbing testHillClimbing(testHillClimbingProblem);
   testHillClimbing.setVelocitys(velocities);
   testHillClimbing.setInitialParameter(initialParameter);
   testHillClimbing.setMaximalStepSize(maximalStepSize);

   // Set Expected values
   arma::Mat<double> expectedParameterHistory;
   expectedParameterHistory.load(testDirectory.string() + dataPath_ + "expected[2.1].mat");

   // Run hill climbing algorithm
  testHillClimbing.optimise();
  // Comparing of candidateParameters
  std::vector<arma::Col<double>> actualParameterHistory = testHillClimbingProblem->getParameterHistory();

  for(std::size_t n = 0; n < expectedParameterHistory.n_cols; ++n) {
    arma::Col<double> expectedParameter = expectedParameterHistory.col(n);
    arma::Col<double> actualParameter = actualParameterHistory.at(n);

    for (std::size_t k = 0; k < expectedParameter.n_elem; ++k) {
        if(std::isfinite(expectedParameter.at(k))) {
          CHECK(actualParameter.at(k) == Approx(expectedParameter.at(k)));
        } else {
          CHECK(actualParameter.at(k) == expectedParameter.at(k));
        }
    }
  }
}

TEST_CASE("Hill climbing (init Test)", "") {

   // Set OptimisationProblem values
   arma::Col<double> upperBounds;
   upperBounds.load(testDirectory.string() + dataPath_ + "upperBounds.mat"); //the parametre is optional

   arma::Col<double> lowerBounds;
   lowerBounds.load(testDirectory.string() + dataPath_ + "lowerBounds.mat"); //the parametre is optional

   arma::Col<double> objectiveValues;
   objectiveValues.load(testDirectory.string() + dataPath_ + "objectiveValues[1.0].mat");

   arma::Col<double> softConstraintsValues;
   softConstraintsValues.load(testDirectory.string() + dataPath_ + "softConstraintsValues[1.0].mat");

   // Init OptimisationProblem
   std::shared_ptr<TestHillClimbingProblem> testHillClimbingProblem(new TestHillClimbingProblem(upperBounds.n_elem));
   testHillClimbingProblem->setUpperBounds(upperBounds);
   testHillClimbingProblem->setLowerBounds(lowerBounds);
   testHillClimbingProblem->setObjectiveValues(objectiveValues);
   testHillClimbingProblem->setSoftConstraintsValues(softConstraintsValues);
   testHillClimbingProblem->setAcceptableObjectiveValue(10.0);

   // Set OptimisationAlgorithm values
   arma::mat velocities;
   velocities.load(testDirectory.string() + dataPath_ + "velocities[1.0].mat");

   // Init OptimisationAlgorithm
   TestHillClimbing testHillClimbing(testHillClimbingProblem);
   testHillClimbing.setVelocitys(velocities);

   arma::Mat<double> expectedParameterHistory;

  SECTION("Check MaximalStepSize"){
    arma::Col<double> initialParameter;
    initialParameter.load(testDirectory.string() + dataPath_ + "initialParameter[null].mat"); //the parametre is optional

    expectedParameterHistory.load(testDirectory.string() + dataPath_ + "expected[1.1].mat");

    testHillClimbing.setInitialParameter(initialParameter);
    testHillClimbing.optimise();

    // Comparing of candidateParameters
    std::vector<arma::Col<double>> actualParameterHistory = testHillClimbingProblem->getParameterHistory();

    for(std::size_t n = 0; n < expectedParameterHistory.n_cols; ++n) {
      arma::Col<double> expectedParameter = expectedParameterHistory.col(n);
      arma::Col<double> actualParameter = actualParameterHistory.at(n);
      std::cout<<actualParameter;
      for (std::size_t k = 0; k < expectedParameter.n_elem; ++k) {
        if(std::isfinite(expectedParameter.at(k))) {
          CHECK(actualParameter.at(k) == Approx(expectedParameter.at(k)));
        } else {
          CHECK(actualParameter.at(k) == expectedParameter.at(k));
        }
      }
    }

  }
/*
  SECTION("Check initialParameter at each limit "){
    arma::Col<double> initialParameter;
    initialParameter.load(testDirectory.string() + dataPath_ + "initialParameter[1.2].mat"); //the parametre is optional

    expectedParameterHistory.load(testDirectory.string() + dataPath_ + "expected[1.2].mat");

    testHillClimbing.setInitialParameter(initialParameter);
    testHillClimbing.optimise();

    // Comparing of candidateParameters
    std::vector<arma::Col<double>> actualParameterHistory = testHillClimbingProblem->getParameterHistory();

    for(std::size_t n = 0; n < expectedParameterHistory.n_cols; ++n) {
      arma::Col<double> expectedParameter = expectedParameterHistory.col(n);
      arma::Col<double> actualParameter = actualParameterHistory.at(n);

      for (std::size_t k = 0; k < expectedParameter.n_elem; ++k) {
        if(std::isfinite(expectedParameter.at(k))) {
          CHECK(actualParameter.at(k) == Approx(expectedParameter.at(k)));
        } else {
          CHECK(actualParameter.at(k) == expectedParameter.at(k));
        }
      }
    }

  }
*/
}
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff/
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

// This one has to come first (includes the config.h)!
#include "main.hxx"

#include <tuple>

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/la/container.hh>
#include <dune/stuff/la/solver.hh>

#include "la_container.hh"

// toggle output
//std::ostream& out = std::cout;
std::ostream& out = DSC_LOG.devnull();

using namespace Dune::Stuff;
using namespace Dune::Stuff::LA;

typedef testing::Types< std::tuple< CommonDenseMatrix< double >, CommonDenseVector< double >, CommonDenseVector< double > >
#if HAVE_EIGEN
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenRowMajorSparseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
#endif // HAVE_EIGEN
#if HAVE_DUNE_ISTL
                      , std::tuple< IstlRowMajorSparseMatrix< double >, IstlDenseVector< double >, IstlDenseVector< double > >
#endif
                      > MatrixVectorCombinations;

template< class MatrixVectorCombination >
struct SolverTest
  : public ::testing::Test
{
  typedef typename std::tuple_element< 0, MatrixVectorCombination >::type MatrixType;
  typedef typename std::tuple_element< 1, MatrixVectorCombination >::type RhsType;
  typedef typename std::tuple_element< 2, MatrixVectorCombination >::type SolutionType;

  typedef Solver< MatrixType > SolverType;

  static void produces_correct_results()
  {
    const size_t dim = 10;
    const MatrixType matrix = ContainerFactory< MatrixType >::create(dim);
    const RhsType rhs = ContainerFactory< RhsType >::create(dim);
    SolutionType solution = ContainerFactory< SolutionType >::create(dim);
    solution.scal(0);

    // dynamic test
    const SolverType solver(matrix);
    solver.apply(rhs, solution);
    if (!solution.almost_equal(rhs))
      DUNE_THROW(Exceptions::results_are_not_as_expected, "Wrong solution!");
    solution.scal(0);

    // static tests
    typedef typename SolverType::MatrixType M;
    std::vector< std::string > opts = SolverType::options();
    if (opts.size() == 0) DUNE_THROW(Exceptions::results_are_not_as_expected, "Solver has no options!");
    for (auto opt : opts) {
      out << "solving with option '" << opt << "' and detailed options" << std::endl;
      Common::Configuration detailed_opts = SolverType::options(opt);
      detailed_opts.report(out, "  ");

      // dynamic tests
      solver.apply(rhs, solution, opt);
      if (!solution.almost_equal(rhs))
        DUNE_THROW(Exceptions::results_are_not_as_expected, "Wrong solution!");
      solution.scal(0);

      solver.apply(rhs, solution, detailed_opts);
      if (!solution.almost_equal(rhs))
        DUNE_THROW(Exceptions::results_are_not_as_expected, "Wrong solution!");
    }
  } // ... produces_correct_results(...)
}; // struct SolverTest

TYPED_TEST_CASE(SolverTest, MatrixVectorCombinations);
TYPED_TEST(SolverTest, behaves_correctly) {
  this->produces_correct_results();
}

<commit_msg>[test] switches a couple exceptions -> test macros<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff/
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

// This one has to come first (includes the config.h)!
#include "main.hxx"

#include <tuple>

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/la/container.hh>
#include <dune/stuff/la/solver.hh>

#include "la_container.hh"

// toggle output
//std::ostream& out = std::cout;
std::ostream& out = DSC_LOG.devnull();

using namespace Dune::Stuff;
using namespace Dune::Stuff::LA;

typedef testing::Types< std::tuple< CommonDenseMatrix< double >, CommonDenseVector< double >, CommonDenseVector< double > >
#if HAVE_EIGEN
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenDenseVector< double > >
                      , std::tuple< EigenDenseMatrix< double >, EigenMappedDenseVector< double >, EigenMappedDenseVector< double > >
                      , std::tuple< EigenRowMajorSparseMatrix< double >, EigenDenseVector< double >, EigenDenseVector< double > >
#endif // HAVE_EIGEN
#if HAVE_DUNE_ISTL
                      , std::tuple< IstlRowMajorSparseMatrix< double >, IstlDenseVector< double >, IstlDenseVector< double > >
#endif
                      > MatrixVectorCombinations;

template< class MatrixVectorCombination >
struct SolverTest
  : public ::testing::Test
{
  typedef typename std::tuple_element< 0, MatrixVectorCombination >::type MatrixType;
  typedef typename std::tuple_element< 1, MatrixVectorCombination >::type RhsType;
  typedef typename std::tuple_element< 2, MatrixVectorCombination >::type SolutionType;

  typedef Solver< MatrixType > SolverType;

  static void produces_correct_results()
  {
    const size_t dim = 10;
    const MatrixType matrix = ContainerFactory< MatrixType >::create(dim);
    const RhsType rhs = ContainerFactory< RhsType >::create(dim);
    SolutionType solution = ContainerFactory< SolutionType >::create(dim);
    solution.scal(0);

    // dynamic test
    const SolverType solver(matrix);
    solver.apply(rhs, solution);
    EXPECT_TRUE(solution.almost_equal(rhs));
    solution.scal(0);

    // static tests
    typedef typename SolverType::MatrixType M;
    std::vector< std::string > opts = SolverType::options();
    if (opts.size() == 0) DUNE_THROW(Exceptions::results_are_not_as_expected, "Solver has no options!");
    for (auto opt : opts) {
      out << "solving with option '" << opt << "' and detailed options" << std::endl;
      Common::Configuration detailed_opts = SolverType::options(opt);
      detailed_opts.report(out, "  ");

      // dynamic tests
      solver.apply(rhs, solution, opt);
      EXPECT_TRUE(solution.almost_equal(rhs));
      solution.scal(0);

      solver.apply(rhs, solution, detailed_opts);
      EXPECT_TRUE(solution.almost_equal(rhs));
    }
  } // ... produces_correct_results(...)
}; // struct SolverTest

TYPED_TEST_CASE(SolverTest, MatrixVectorCombinations);
TYPED_TEST(SolverTest, behaves_correctly) {
  this->produces_correct_results();
}

<|endoftext|>


<commit_before>/*
 * Wrapper for execve().  Allows building the argument list
 * dynamically, and automatically de-consts the argument strings.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "exec.hxx"

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

void
Exec::SetEnv(const char *name, const char *value)
{
    assert(name != nullptr);
    assert(value != nullptr);

    const size_t name_length = strlen(name);
    const size_t value_length = strlen(name);

    assert(name_length > 0);

    char *buffer = (char *)malloc(name_length + 1 + value_length + 1);
    memcpy(buffer, name, name_length);
    buffer[name_length] = '=';
    memcpy(buffer + name_length + 1, value, value_length);
    buffer[name_length + 1 + value_length] = 0;

    PutEnv(buffer);

    /* no need to free this allocation; this process will be replaced
       soon by execve() anyway */
}

void
Exec::DoExec()
{
    assert(!args.empty());

    args.push_back(nullptr);

    const char *path = args.front();
    const char *slash = strrchr(path, '/');
    if (slash != nullptr && slash[1] != 0)
        args.front() = const_cast<char *>(slash + 1);

    env.push_back(nullptr);

    execve(path, args.raw(), env.raw());

    fprintf(stderr, "failed to execute %s: %s\n", path, strerror(errno));
    _exit(1);
}
<commit_msg>exec: fix value corruption in SetEnv()<commit_after>/*
 * Wrapper for execve().  Allows building the argument list
 * dynamically, and automatically de-consts the argument strings.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "exec.hxx"

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

void
Exec::SetEnv(const char *name, const char *value)
{
    assert(name != nullptr);
    assert(value != nullptr);

    const size_t name_length = strlen(name);
    const size_t value_length = strlen(value);

    assert(name_length > 0);

    char *buffer = (char *)malloc(name_length + 1 + value_length + 1);
    memcpy(buffer, name, name_length);
    buffer[name_length] = '=';
    memcpy(buffer + name_length + 1, value, value_length);
    buffer[name_length + 1 + value_length] = 0;

    PutEnv(buffer);

    /* no need to free this allocation; this process will be replaced
       soon by execve() anyway */
}

void
Exec::DoExec()
{
    assert(!args.empty());

    args.push_back(nullptr);

    const char *path = args.front();
    const char *slash = strrchr(path, '/');
    if (slash != nullptr && slash[1] != 0)
        args.front() = const_cast<char *>(slash + 1);

    env.push_back(nullptr);

    execve(path, args.raw(), env.raw());

    fprintf(stderr, "failed to execute %s: %s\n", path, strerror(errno));
    _exit(1);
}
<|endoftext|>


<commit_before>/* * * * * * * * * * * * *\
|*             ╔═╗ v0.3  *|
|* ╔═╦═╦═══╦═══╣ ╚═╦═╦═╗ *|
|* ║ ╔═╣ '╔╬═╗╚╣ ║ ║  '║ *|
|* ╚═╝ ╚═══╩═══╩═╩═╣ ╔═╝ *|
|* * * * * * * * * ╚═╝ * *|
|* Manipulation tool for *|
|*    ESRI Shapefiles    *|
|* * * * * * * * * * * * *|
|* http://www.npolar.no/ *|
\* * * * * * * * * * * * */

#include "file.hpp"

namespace reshp
{
    const file::endian::type file::endian::native = file::endian::detect();

    file::endian::type file::endian::detect()
    {
        union { uint32_t dw; uint8_t b[4]; }; dw = 0xAABBCCDD;

        if(b[0] == 0xAA && b[1] == 0xBB && b[2] == 0xCC && b[3] == 0xDD)
            return file::endian::big;

        if(b[0] == 0xDD && b[1] == 0xCC && b[2] == 0xBB && b[3] == 0xAA)
            return file::endian::little;

        return file::endian::unknown;
    }

    file::file() :
        file_(NULL),
        endian_(file::endian::native),
        eol_(file::eol::detect),
        modes_(file::mode::read),
        size_(0)
    {
    }

    file::~file()
    {
        close();
    }

    bool file::clear(const std::string& filename)
    {
        if(file::exists(filename))
        {
            FILE* fp = fopen(filename.c_str(), "wb");

            if(fp)
            {
                fclose(fp);
                return true;
            }
        }

        return false;
    }

    bool file::exists(const std::string& filename)
    {
        FILE* fp = fopen(filename.c_str(), "rb");

        if(fp)
        {
            fclose(fp);
            return true;
        }

        return false;
    }

    bool file::remove(const std::string& filename)
    {
        return (::remove(filename.c_str()) == 0 ? true : false);
    }

    bool file::rename(const std::string& oldname, const std::string& newname)
    {
        return (::rename(oldname.c_str(), newname.c_str()) == 0 ? true : false);
    }

    size_t file::size(const std::string& filename)
    {
        FILE* fp = fopen(filename.c_str(), "rb");

        if(fp)
        {
            fseek(fp, 0, SEEK_END);
            long int bytes = ftell(fp);

            if(bytes >= 0)
            {
                fclose(fp);
                return static_cast<size_t>(bytes);
            }

            fclose(fp);
        }

        return 0;
    }

    file::time file::timestamp(const std::string& filename)
    {
        file::time ft;

        memset(ft.accessed.data, 0, sizeof(ft.accessed.data));
        memset(ft.modified.data, 0, sizeof(ft.modified.data));

        if(file::exists(filename))
        {
            bool success = false;

        #if defined(__linux__)
            struct stat attr;
            success = (::stat(filename.c_str(), &attr) == 0);
        #elif defined(__WIN32)
            struct _stat attr;
            success = (::_stat(filename, &attr) == 0);
        #endif

            if(success)
            {
                struct tm* ltaccessed   = localtime(&attr.st_atime);
                ft.accessed.year        = ltaccessed->tm_year + 1900;
                ft.accessed.month       = ltaccessed->tm_mon + 1;
                ft.accessed.day         = ltaccessed->tm_mday;
                ft.accessed.hour        = ltaccessed->tm_hour;
                ft.accessed.minute      = ltaccessed->tm_min;
                ft.accessed.second      = ltaccessed->tm_sec;

                struct tm* ltmodified   = localtime(&attr.st_mtime);
                ft.modified.year        = ltmodified->tm_year + 1900;
                ft.modified.month       = ltmodified->tm_mon + 1;
                ft.modified.day         = ltmodified->tm_mday;
                ft.modified.hour        = ltaccessed->tm_hour;
                ft.modified.minute      = ltaccessed->tm_min;
                ft.modified.second      = ltaccessed->tm_sec;
            }
        }

        return ft;
    }

    bool file::clear()
    {
        if(file_ && (modes_ & file::mode::write))
        {
            char fmodes[4] = { 'w', 0, 0, 0 };
            uint8_t m = 1;

            if(modes_ & file::mode::read)
                fmodes[m++] = 'r';

            if(modes_ & file::mode::binary)
                fmodes[m++] = 'b';

            if((file_ = freopen(NULL, fmodes, file_)))
            {
                size_ = 0;
                return true;
            }
        }

        return false;
    }

    void file::close()
    {
        if(file_)
        {
            fclose(file_);
            file_ = NULL;
        }

        endian_ = file::endian::native;
        eol_    = file::eol::detect;
        modes_  = file::mode::read;
        size_   = 0;
    }

    bool file::eof() const
    {
        if(file_)
        {
            if(feof(file_))
                return true;

            char c = fgetc(file_);
            if(c == EOF) return true;
            else ungetc(c, file_);
        }

        return false;
    }

    bool file::open(const std::string& filename, const file::mode::flags modes, const file::eol::type eol)
    {
        close();

        char fmodes[4] = { 0, 0, 0, 0 };
        uint8_t m = 0;

        if(modes & file::mode::read)
            fmodes[m++] = 'r';

        if(modes & file::mode::write)
            fmodes[m++] = 'a';

        if(modes & file::mode::binary)
            fmodes[m++] = 'b';

        if((file_ = fopen(filename.c_str(), fmodes)))
        {
            if(!(modes & file::mode::binary))
            {
                if(eol == file::eol::detect)
                {
                    fseek(file_, 0, SEEK_SET);

                    for(char c = fgetc(file_); c != EOF; c = fgetc(file_))
                    {
                        if(c == '\r')
                        {
                            eol_ = (fgetc(file_) == '\n' ? file::eol::crlf : file::eol::cr);
                            ungetc(c, file_);
                            break;
                        }
                        else if(c == '\n')
                        {
                            eol_ = (fgetc(file_) == '\r' ? file::eol::lfcr : file::eol::lf);
                            ungetc(c, file_);
                            break;
                        }
                    }

                    if(eol_ == file::eol::detect)
                    {
                    #if defined(__WIN32)
                        eol_ = file::eol::crlf;
                    #else
                        eol_ = file::eol::lf;
                    #endif
                    }

                    clearerr(file_);
                }
                else eol_ = eol;
            }

            fseek(file_, 0, SEEK_END);
            size_ = static_cast<size_t>(ftell(file_));

            if(!((modes_ = modes) & file::mode::write))
                fseek(file_, 0, SEEK_SET);

            return true;
        }

        return false;
    }

    bool file::opened() const
    {
        return (file_ ? true : false);
    }

    bool file::seek(const long position, const bool relative)
    {
        if(file_)
        {
            return (fseek(file_, position, (relative ? SEEK_CUR : SEEK_SET)) == 0);
        }

        return false;
    }

    size_t file::size() const
    {
        return size_;
    }

    long file::tell() const
    {
        if(file_)
            return ftell(file_);

        return -1;
    }

    bool file::read(char* dst, size_t bytes)
    {
        if(file_ && (modes_ & file::mode::read))
            if(fread(dst, bytes, 1, file_))
                return true;

        return false;
    }

    bool file::gets(std::string& str)
    {
        if(file_ && (modes_ & file::mode::read))
        {
            size_t len = 0;
            char* buf = NULL;

            if(modes_ & file::mode::binary)
            {
                for(char c = fgetc(file_); c != EOF; c = fgetc(file_), ++len)
                    if(c == '\0')
                        break;

                if(len++ && (fseek(file_, -len, SEEK_CUR) == 0))
                {
                    if((buf = new char[len]()))
                    {
                        if(!fread(buf, len, 1, file_))
                        {
                            delete [] buf;
                            return false;
                        }

                        str = buf;
                        delete [] buf;
                    }
                }

                return true;
            }
            else
            {
                if((buf = new char[size_]()))
                {
                    if(fscanf(file_, "%s", buf) == 1)
                    {
                        str = buf;
                        delete [] buf;
                        return true;
                    }

                    delete [] buf;
                }
            }
        }

        return false;
    }

    bool file::getline(std::string& str)
    {
        if(file_ && (modes_ & file::mode::read) && !(modes_ & file::mode::binary))
        {
            char eol[2] = { 0, 0 };

            switch(eol_)
            {
            case file::eol::cr:     memcpy(eol, "\r", 1);   break;
            case file::eol::crlf:   memcpy(eol, "\r\r", 2); break;
            case file::eol::lf:     memcpy(eol, "\n", 1);   break;
            case file::eol::lfcr:   memcpy(eol, "\n\r", 2); break;
            default:
                return false;
            }

            // Remove leading whitespace characters
            for(char c = fgetc(file_); c != EOF; ++c)
            {
                if(c != ' ' && c != '\t' && c != '\v' && c != '\r' && c != '\n')
                {
                    ungetc(c, file_);
                    break;
                }
                else continue;
            }

            for(char c = fgetc(file_), cc; c != EOF; c = fgetc(file_))
            {
                if(c == eol[0])
                {
                    if(!eol[1] || (eol[1] && (cc = fgetc(file_)) == eol[1]))
                        break;

                    else if(eol[1])
                        ungetc(cc, file_);
                }

                str += c;
            }

            return true;
        }

        return false;
    }

    file& file::operator>> (char& c)
    {
        read(&c, 1);
        return *this;
    }

    file& file::operator>> (int8_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (int16_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (int32_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (uint8_t& u)
    {
        geti(u);
        return *this;
    }

    file& file::operator>> (uint16_t& u)
    {
        geti(u);
        return *this;
    }

    file& file::operator>> (uint32_t& u)
    {
        geti(u);
        return *this;
    }

    file& file::operator>> (float& f)
    {
        getf(f);
        return *this;
    }

    file& file::operator>> (double& d)
    {
        getf(d);
        return *this;
    }

    file& file::operator>> (std::string& str)
    {
        gets(str);
        return *this;
    }

    #if __WORDSIZE == 64
    file& file::operator>> (int64_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (uint64_t& u)
    {
        geti(u);
        return *this;
    }
    #endif

    bool file::write(const char* src, size_t bytes)
    {
        if(file_ && (modes_ & file::mode::write))
        {
            if(fwrite(src, bytes, 1, file_))
            {
                size_ += bytes;
                return true;
            }
        }

        return false;
    }

    bool file::putline(const std::string& str)
    {
        if(file_ && (modes_ & file::mode::write) && !(modes_ & file::mode::binary))
        {
            if(ftell(file_) > 0)
            {
                switch(eol_)
                {
                case file::eol::cr:     size_ += fwrite("\r", 1, 1, file_);     break;
                case file::eol::crlf:   size_ += fwrite("\r\n", 1, 2, file_);   break;
                case file::eol::lf:     size_ += fwrite("\n", 1, 1, file_);     break;
                case file::eol::lfcr:   size_ += fwrite("\n\r", 1, 2, file_);   break;
                default:;
                }
            }

            if(fwrite(str.c_str(), str.length(), 1, file_))
            {
                size_ += str.length();
                return true;
            }
        }

        return false;
    }

    bool file::puts(const std::string& str)
    {
        if(file_ && (modes_ & file::mode::write))
        {
            if(fputs(str.c_str(), file_) != EOF)
            {
                size_ += str.length();

                if(fputc((modes_ & file::mode::binary) ? '\0' : ' ', file_) != EOF)
                {
                    size_ += 1;
                    return true;
                }
            }
        }

        return false;
    }

    file& file::operator<< (const char c)
    {
        write(&c, 1);
        return *this;
    }

    file& file::operator<< (const int8_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const int16_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const int32_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const uint8_t u)
    {
        puti(u);
        return *this;
    }

    file& file::operator<< (const uint16_t u)
    {
        puti(u);
        return *this;
    }

    file& file::operator<< (const uint32_t u)
    {
        puti(u);
        return *this;
    }

    file& file::operator<< (const float f)
    {
        putf(f);
        return *this;
    }

    file& file::operator<< (const double d)
    {
        putf(d);
        return *this;
    }

    file& file::operator<< (const std::string& str)
    {
        puts(str);
        return *this;
    }

    #if __WORDSIZE == 64
    file& file::operator<< (const int64_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const uint64_t u)
    {
        puti(u);
        return *this;
    }
    #endif
}
<commit_msg>Fixed file::timestamp() bug for Windows builds<commit_after>/* * * * * * * * * * * * *\
|*             ╔═╗ v0.3  *|
|* ╔═╦═╦═══╦═══╣ ╚═╦═╦═╗ *|
|* ║ ╔═╣ '╔╬═╗╚╣ ║ ║  '║ *|
|* ╚═╝ ╚═══╩═══╩═╩═╣ ╔═╝ *|
|* * * * * * * * * ╚═╝ * *|
|* Manipulation tool for *|
|*    ESRI Shapefiles    *|
|* * * * * * * * * * * * *|
|* http://www.npolar.no/ *|
\* * * * * * * * * * * * */

#include "file.hpp"

namespace reshp
{
    const file::endian::type file::endian::native = file::endian::detect();

    file::endian::type file::endian::detect()
    {
        union { uint32_t dw; uint8_t b[4]; }; dw = 0xAABBCCDD;

        if(b[0] == 0xAA && b[1] == 0xBB && b[2] == 0xCC && b[3] == 0xDD)
            return file::endian::big;

        if(b[0] == 0xDD && b[1] == 0xCC && b[2] == 0xBB && b[3] == 0xAA)
            return file::endian::little;

        return file::endian::unknown;
    }

    file::file() :
        file_(NULL),
        endian_(file::endian::native),
        eol_(file::eol::detect),
        modes_(file::mode::read),
        size_(0)
    {
    }

    file::~file()
    {
        close();
    }

    bool file::clear(const std::string& filename)
    {
        if(file::exists(filename))
        {
            FILE* fp = fopen(filename.c_str(), "wb");

            if(fp)
            {
                fclose(fp);
                return true;
            }
        }

        return false;
    }

    bool file::exists(const std::string& filename)
    {
        FILE* fp = fopen(filename.c_str(), "rb");

        if(fp)
        {
            fclose(fp);
            return true;
        }

        return false;
    }

    bool file::remove(const std::string& filename)
    {
        return (::remove(filename.c_str()) == 0 ? true : false);
    }

    bool file::rename(const std::string& oldname, const std::string& newname)
    {
        return (::rename(oldname.c_str(), newname.c_str()) == 0 ? true : false);
    }

    size_t file::size(const std::string& filename)
    {
        FILE* fp = fopen(filename.c_str(), "rb");

        if(fp)
        {
            fseek(fp, 0, SEEK_END);
            long int bytes = ftell(fp);

            if(bytes >= 0)
            {
                fclose(fp);
                return static_cast<size_t>(bytes);
            }

            fclose(fp);
        }

        return 0;
    }

    file::time file::timestamp(const std::string& filename)
    {
        file::time ft;

        memset(ft.accessed.data, 0, sizeof(ft.accessed.data));
        memset(ft.modified.data, 0, sizeof(ft.modified.data));

        if(file::exists(filename))
        {
            bool success = false;

        #if defined(__linux__)
            struct stat attr;
            success = (::stat(filename.c_str(), &attr) == 0);
        #elif defined(__WIN32)
            struct _stat attr;
            success = (::_stat(filename.c_str(), &attr) == 0);
        #endif

            if(success)
            {
                struct tm* ltaccessed   = localtime(&attr.st_atime);
                ft.accessed.year        = ltaccessed->tm_year + 1900;
                ft.accessed.month       = ltaccessed->tm_mon + 1;
                ft.accessed.day         = ltaccessed->tm_mday;
                ft.accessed.hour        = ltaccessed->tm_hour;
                ft.accessed.minute      = ltaccessed->tm_min;
                ft.accessed.second      = ltaccessed->tm_sec;

                struct tm* ltmodified   = localtime(&attr.st_mtime);
                ft.modified.year        = ltmodified->tm_year + 1900;
                ft.modified.month       = ltmodified->tm_mon + 1;
                ft.modified.day         = ltmodified->tm_mday;
                ft.modified.hour        = ltaccessed->tm_hour;
                ft.modified.minute      = ltaccessed->tm_min;
                ft.modified.second      = ltaccessed->tm_sec;
            }
        }

        return ft;
    }

    bool file::clear()
    {
        if(file_ && (modes_ & file::mode::write))
        {
            char fmodes[4] = { 'w', 0, 0, 0 };
            uint8_t m = 1;

            if(modes_ & file::mode::read)
                fmodes[m++] = 'r';

            if(modes_ & file::mode::binary)
                fmodes[m++] = 'b';

            if((file_ = freopen(NULL, fmodes, file_)))
            {
                size_ = 0;
                return true;
            }
        }

        return false;
    }

    void file::close()
    {
        if(file_)
        {
            fclose(file_);
            file_ = NULL;
        }

        endian_ = file::endian::native;
        eol_    = file::eol::detect;
        modes_  = file::mode::read;
        size_   = 0;
    }

    bool file::eof() const
    {
        if(file_)
        {
            if(feof(file_))
                return true;

            char c = fgetc(file_);
            if(c == EOF) return true;
            else ungetc(c, file_);
        }

        return false;
    }

    bool file::open(const std::string& filename, const file::mode::flags modes, const file::eol::type eol)
    {
        close();

        char fmodes[4] = { 0, 0, 0, 0 };
        uint8_t m = 0;

        if(modes & file::mode::read)
            fmodes[m++] = 'r';

        if(modes & file::mode::write)
            fmodes[m++] = 'a';

        if(modes & file::mode::binary)
            fmodes[m++] = 'b';

        if((file_ = fopen(filename.c_str(), fmodes)))
        {
            if(!(modes & file::mode::binary))
            {
                if(eol == file::eol::detect)
                {
                    fseek(file_, 0, SEEK_SET);

                    for(char c = fgetc(file_); c != EOF; c = fgetc(file_))
                    {
                        if(c == '\r')
                        {
                            eol_ = (fgetc(file_) == '\n' ? file::eol::crlf : file::eol::cr);
                            ungetc(c, file_);
                            break;
                        }
                        else if(c == '\n')
                        {
                            eol_ = (fgetc(file_) == '\r' ? file::eol::lfcr : file::eol::lf);
                            ungetc(c, file_);
                            break;
                        }
                    }

                    if(eol_ == file::eol::detect)
                    {
                    #if defined(__WIN32)
                        eol_ = file::eol::crlf;
                    #else
                        eol_ = file::eol::lf;
                    #endif
                    }

                    clearerr(file_);
                }
                else eol_ = eol;
            }

            fseek(file_, 0, SEEK_END);
            size_ = static_cast<size_t>(ftell(file_));

            if(!((modes_ = modes) & file::mode::write))
                fseek(file_, 0, SEEK_SET);

            return true;
        }

        return false;
    }

    bool file::opened() const
    {
        return (file_ ? true : false);
    }

    bool file::seek(const long position, const bool relative)
    {
        if(file_)
        {
            return (fseek(file_, position, (relative ? SEEK_CUR : SEEK_SET)) == 0);
        }

        return false;
    }

    size_t file::size() const
    {
        return size_;
    }

    long file::tell() const
    {
        if(file_)
            return ftell(file_);

        return -1;
    }

    bool file::read(char* dst, size_t bytes)
    {
        if(file_ && (modes_ & file::mode::read))
            if(fread(dst, bytes, 1, file_))
                return true;

        return false;
    }

    bool file::gets(std::string& str)
    {
        if(file_ && (modes_ & file::mode::read))
        {
            size_t len = 0;
            char* buf = NULL;

            if(modes_ & file::mode::binary)
            {
                for(char c = fgetc(file_); c != EOF; c = fgetc(file_), ++len)
                    if(c == '\0')
                        break;

                if(len++ && (fseek(file_, -len, SEEK_CUR) == 0))
                {
                    if((buf = new char[len]()))
                    {
                        if(!fread(buf, len, 1, file_))
                        {
                            delete [] buf;
                            return false;
                        }

                        str = buf;
                        delete [] buf;
                    }
                }

                return true;
            }
            else
            {
                if((buf = new char[size_]()))
                {
                    if(fscanf(file_, "%s", buf) == 1)
                    {
                        str = buf;
                        delete [] buf;
                        return true;
                    }

                    delete [] buf;
                }
            }
        }

        return false;
    }

    bool file::getline(std::string& str)
    {
        if(file_ && (modes_ & file::mode::read) && !(modes_ & file::mode::binary))
        {
            char eol[2] = { 0, 0 };

            switch(eol_)
            {
            case file::eol::cr:     memcpy(eol, "\r", 1);   break;
            case file::eol::crlf:   memcpy(eol, "\r\r", 2); break;
            case file::eol::lf:     memcpy(eol, "\n", 1);   break;
            case file::eol::lfcr:   memcpy(eol, "\n\r", 2); break;
            default:
                return false;
            }

            // Remove leading whitespace characters
            for(char c = fgetc(file_); c != EOF; ++c)
            {
                if(c != ' ' && c != '\t' && c != '\v' && c != '\r' && c != '\n')
                {
                    ungetc(c, file_);
                    break;
                }
                else continue;
            }

            for(char c = fgetc(file_), cc; c != EOF; c = fgetc(file_))
            {
                if(c == eol[0])
                {
                    if(!eol[1] || (eol[1] && (cc = fgetc(file_)) == eol[1]))
                        break;

                    else if(eol[1])
                        ungetc(cc, file_);
                }

                str += c;
            }

            return true;
        }

        return false;
    }

    file& file::operator>> (char& c)
    {
        read(&c, 1);
        return *this;
    }

    file& file::operator>> (int8_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (int16_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (int32_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (uint8_t& u)
    {
        geti(u);
        return *this;
    }

    file& file::operator>> (uint16_t& u)
    {
        geti(u);
        return *this;
    }

    file& file::operator>> (uint32_t& u)
    {
        geti(u);
        return *this;
    }

    file& file::operator>> (float& f)
    {
        getf(f);
        return *this;
    }

    file& file::operator>> (double& d)
    {
        getf(d);
        return *this;
    }

    file& file::operator>> (std::string& str)
    {
        gets(str);
        return *this;
    }

    #if __WORDSIZE == 64
    file& file::operator>> (int64_t& s)
    {
        geti(s);
        return *this;
    }

    file& file::operator>> (uint64_t& u)
    {
        geti(u);
        return *this;
    }
    #endif

    bool file::write(const char* src, size_t bytes)
    {
        if(file_ && (modes_ & file::mode::write))
        {
            if(fwrite(src, bytes, 1, file_))
            {
                size_ += bytes;
                return true;
            }
        }

        return false;
    }

    bool file::putline(const std::string& str)
    {
        if(file_ && (modes_ & file::mode::write) && !(modes_ & file::mode::binary))
        {
            if(ftell(file_) > 0)
            {
                switch(eol_)
                {
                case file::eol::cr:     size_ += fwrite("\r", 1, 1, file_);     break;
                case file::eol::crlf:   size_ += fwrite("\r\n", 1, 2, file_);   break;
                case file::eol::lf:     size_ += fwrite("\n", 1, 1, file_);     break;
                case file::eol::lfcr:   size_ += fwrite("\n\r", 1, 2, file_);   break;
                default:;
                }
            }

            if(fwrite(str.c_str(), str.length(), 1, file_))
            {
                size_ += str.length();
                return true;
            }
        }

        return false;
    }

    bool file::puts(const std::string& str)
    {
        if(file_ && (modes_ & file::mode::write))
        {
            if(fputs(str.c_str(), file_) != EOF)
            {
                size_ += str.length();

                if(fputc((modes_ & file::mode::binary) ? '\0' : ' ', file_) != EOF)
                {
                    size_ += 1;
                    return true;
                }
            }
        }

        return false;
    }

    file& file::operator<< (const char c)
    {
        write(&c, 1);
        return *this;
    }

    file& file::operator<< (const int8_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const int16_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const int32_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const uint8_t u)
    {
        puti(u);
        return *this;
    }

    file& file::operator<< (const uint16_t u)
    {
        puti(u);
        return *this;
    }

    file& file::operator<< (const uint32_t u)
    {
        puti(u);
        return *this;
    }

    file& file::operator<< (const float f)
    {
        putf(f);
        return *this;
    }

    file& file::operator<< (const double d)
    {
        putf(d);
        return *this;
    }

    file& file::operator<< (const std::string& str)
    {
        puts(str);
        return *this;
    }

    #if __WORDSIZE == 64
    file& file::operator<< (const int64_t s)
    {
        puti(s);
        return *this;
    }

    file& file::operator<< (const uint64_t u)
    {
        puti(u);
        return *this;
    }
    #endif
}
<|endoftext|>