<commit_before>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

/**
 * @file
 *   @brief Definition of UDP connection (server) for unmanned vehicles
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QtGlobal>
#include <QTimer>
#include <QList>
#include <QDebug>
#include <QMutexLocker>
#include <QNetworkProxy>
#include <QNetworkInterface>
#include <iostream>

#include "UDPLink.h"
#include "QGC.h"
#include <QHostInfo>

#define REMOVE_GONE_HOSTS 0

static const char* kZeroconfRegistration = "_qgroundcontrol._udp";

static bool is_ip(const QString& address)
{
    int a,b,c,d;
    if (sscanf(address.toStdString().c_str(), "%d.%d.%d.%d", &a, &b, &c, &d) != 4
            && strcmp("::1", address.toStdString().c_str())) {
        return false;
    } else {
        return true;
    }
}

static QString get_ip_address(const QString& address)
{
    if(is_ip(address))
        return address;
    // Need to look it up
    QHostInfo info = QHostInfo::fromName(address);
    if (info.error() == QHostInfo::NoError)
    {
        QList<QHostAddress> hostAddresses = info.addresses();
        QHostAddress address;
        for (int i = 0; i < hostAddresses.size(); i++)
        {
            // Exclude all IPv6 addresses
            if (!hostAddresses.at(i).toString().contains(":"))
            {
                return hostAddresses.at(i).toString();
            }
        }
    }
    return QString("");
}

UDPLink::UDPLink(SharedLinkConfigurationPointer& config)
    : LinkInterface(config)
#if defined(QGC_ZEROCONF_ENABLED)
    , _dnssServiceRef(NULL)
#endif
    , _running(false)
    , _socket(NULL)
    , _udpConfig(qobject_cast<UDPConfiguration*>(config.data()))
    , _connectState(false)
{
    Q_ASSERT(_udpConfig);
    moveToThread(this);
}

UDPLink::~UDPLink()
{
    _disconnect();
    // Tell the thread to exit
    _running = false;
    quit();
    // Wait for it to exit
    wait();
    this->deleteLater();
}

/**
 * @brief Runs the thread
 *
 **/
void UDPLink::run()
{
    if(_hardwareConnect()) {
        exec();
    }
    if (_socket) {
        _deregisterZeroconf();
        _socket->close();
    }
}

void UDPLink::_restartConnection()
{
    if(this->isConnected())
    {
        _disconnect();
        _connect();
    }
}

QString UDPLink::getName() const
{
    return _udpConfig->name();
}

void UDPLink::addHost(const QString& host)
{
    _udpConfig->addHost(host);
}

void UDPLink::removeHost(const QString& host)
{
    _udpConfig->removeHost(host);
}

void UDPLink::_writeBytes(const QByteArray data)
{
    if (!_socket)
        return;

    QStringList goneHosts;
    // Send to all connected systems
    QString host;
    int port;
    if(_udpConfig->firstHost(host, port)) {
        do {
            QHostAddress currentHost(host);
            if(_socket->writeDatagram(data, currentHost, (quint16)port) < 0) {
                // This host is gone. Add to list to be removed
                // We should keep track of hosts that were manually added (static) and
                // hosts that were added because we heard from them (dynamic). Only
                // dynamic hosts should be removed and even then, after a few tries, not
                // the first failure. In the mean time, we don't remove anything.
                if(REMOVE_GONE_HOSTS) {
                    goneHosts.append(host);
                }
            } else {
                // Only log rate if data actually got sent. Not sure about this as
                // "host not there" takes time too regardless of size of data. In fact,
                // 1 byte or "UDP frame size" bytes are the same as that's the data
                // unit sent by UDP.
                _logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch());
            }
        } while (_udpConfig->nextHost(host, port));
        //-- Remove hosts that are no longer there
        foreach (const QString& ghost, goneHosts) {
            _udpConfig->removeHost(ghost);
        }
    }
}

/**
 * @brief Read a number of bytes from the interface.
 **/
void UDPLink::readBytes()
{
    QByteArray databuffer;
    while (_socket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(_socket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        _socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        databuffer.append(datagram);
        //-- Wait a bit before sending it over
        if(databuffer.size() > 10 * 1024) {
            emit bytesReceived(this, databuffer);
            databuffer.clear();
        }
        _logInputDataRate(datagram.length(), QDateTime::currentMSecsSinceEpoch());
        // TODO This doesn't validade the sender. Anything sending UDP packets to this port gets
        // added to the list and will start receiving datagrams from here. Even a port scanner
        // would trigger this.
        // Add host to broadcast list if not yet present, or update its port
        _udpConfig->addHost(sender.toString(), (int)senderPort);
    }
    //-- Send whatever is left
    if(databuffer.size()) {
        emit bytesReceived(this, databuffer);
    }
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
void UDPLink::_disconnect(void)
{
    _running = false;
    quit();
    wait();
    if (_socket) {
        // Make sure delete happen on correct thread
        _socket->deleteLater();
        _socket = NULL;
        emit disconnected();
    }
    _connectState = false;
}

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
bool UDPLink::_connect(void)
{
    if(this->isRunning() || _running)
    {
        _running = false;
        quit();
        wait();
    }
    _running = true;
    start(NormalPriority);
    return true;
}

bool UDPLink::_hardwareConnect()
{
    if (_socket) {
        delete _socket;
        _socket = NULL;
    }
    QHostAddress host = QHostAddress::AnyIPv4;
    _socket = new QUdpSocket();
    _socket->setProxy(QNetworkProxy::NoProxy);
    _connectState = _socket->bind(host, _udpConfig->localPort(), QAbstractSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
    if (_connectState) {
        //-- Make sure we have a large enough IO buffers
#ifdef __mobile__
        _socket->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption,     64 * 1024);
        _socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 128 * 1024);
#else
        _socket->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption,    256 * 1024);
        _socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 512 * 1024);
#endif
        _registerZeroconf(_udpConfig->localPort(), kZeroconfRegistration);
        QObject::connect(_socket, &QUdpSocket::readyRead, this, &UDPLink::readBytes);
        emit connected();
    } else {
        emit communicationError("UDP Link Error", "Error binding UDP port");
    }
    return _connectState;
}

/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
bool UDPLink::isConnected() const
{
    return _connectState;
}

qint64 UDPLink::getConnectionSpeed() const
{
    return 54000000; // 54 Mbit
}

qint64 UDPLink::getCurrentInDataRate() const
{
    return 0;
}

qint64 UDPLink::getCurrentOutDataRate() const
{
    return 0;
}

void UDPLink::_registerZeroconf(uint16_t port, const std::string &regType)
{
#if defined(QGC_ZEROCONF_ENABLED)
    DNSServiceErrorType result = DNSServiceRegister(&_dnssServiceRef, 0, 0, 0,
        regType.c_str(),
        NULL,
        NULL,
        htons(port),
        0,
        NULL,
        NULL,
        NULL);
    if (result != kDNSServiceErr_NoError)
    {
        emit communicationError("UDP Link Error", "Error registering Zeroconf");
        _dnssServiceRef = NULL;
    }
#else
    Q_UNUSED(port);
    Q_UNUSED(regType);
#endif
}

void UDPLink::_deregisterZeroconf()
{
#if defined(QGC_ZEROCONF_ENABLED)
    if (_dnssServiceRef)
     {
         DNSServiceRefDeallocate(_dnssServiceRef);
         _dnssServiceRef = NULL;
     }
#endif
}

//--------------------------------------------------------------------------
//-- UDPConfiguration

UDPConfiguration::UDPConfiguration(const QString& name) : LinkConfiguration(name)
{
    _localPort = QGC_UDP_LOCAL_PORT;
}

UDPConfiguration::UDPConfiguration(UDPConfiguration* source) : LinkConfiguration(source)
{
    _localPort = source->localPort();
    QString host;
    int port;
    _hostList.clear();
    if(source->firstHost(host, port)) {
        do {
            addHost(host, port);
        } while(source->nextHost(host, port));
    }
}

void UDPConfiguration::copyFrom(LinkConfiguration *source)
{
    LinkConfiguration::copyFrom(source);
    UDPConfiguration* usource = dynamic_cast<UDPConfiguration*>(source);
    Q_ASSERT(usource != NULL);
    _localPort = usource->localPort();
    _hosts.clear();
    QString host;
    int port;
    if(usource->firstHost(host, port)) {
        do {
            addHost(host, port);
        } while(usource->nextHost(host, port));
    }
}

/**
 * @param host Hostname in standard formatt, e.g. localhost:14551 or 192.168.1.1:14551
 */
void UDPConfiguration::addHost(const QString host)
{
    // Handle x.x.x.x:p
    if (host.contains(":"))
    {
        addHost(host.split(":").first(), host.split(":").last().toInt());
    }
    // If no port, use default
    else
    {
        addHost(host, (int)_localPort);
    }
}

void UDPConfiguration::addHost(const QString& host, int port)
{
    bool changed = false;
    QMutexLocker locker(&_confMutex);
    if(_hosts.contains(host)) {
        if(_hosts[host] != port) {
            _hosts[host] = port;
            changed = true;
        }
    } else {
        QString ipAdd = get_ip_address(host);
        if(ipAdd.isEmpty()) {
            qWarning() << "UDP:" << "Could not resolve host:" << host << "port:" << port;
        } else {
            // In simulation and testing setups the vehicle and the GCS can be
            // running on the same host. This leads to packets arriving through
            // the local network or the loopback adapter, which makes it look
            // like the vehicle is connected through two different links,
            // complicating routing.
            //
            // We detect this case and force all traffic to a simulated instance
            // onto the local loopback interface.
            bool not_local = true;
            // Run through all IPv4 interfaces and check if their canonical
            // IP address in string representation matches the source IP address
            foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {
                if (address.protocol() == QAbstractSocket::IPv4Protocol) {
                    if (ipAdd.endsWith(address.toString())) {
                        // This is a local address of the same host
                        not_local = false;
                    }
                }
            }
            if (not_local) {
                // This is a normal remote host, add it using its IPv4 address
                _hosts[ipAdd] = port;
                //qDebug() << "UDP:" << "Adding Host:" << ipAdd << ":" << port;
            } else {
                // It is localhost, so talk to it through the IPv4 loopback interface
                _hosts["127.0.0.1"] = port;
            }
            changed = true;
        }
    }
    if(changed) {
        _updateHostList();
    }
}

void UDPConfiguration::removeHost(const QString host)
{
    QMutexLocker locker(&_confMutex);
    QString tHost = host;
    if (tHost.contains(":")) {
        tHost = tHost.split(":").first();
    }
    tHost = tHost.trimmed();
    QMap<QString, int>::iterator i = _hosts.find(tHost);
    if(i != _hosts.end()) {
        //qDebug() << "UDP:" << "Removed host:" << host;
        _hosts.erase(i);
    } else {
        qWarning() << "UDP:" << "Could not remove unknown host:" << host;
    }
    _updateHostList();
}

bool UDPConfiguration::firstHost(QString& host, int& port)
{
    _confMutex.lock();
    _it = _hosts.begin();
    if(_it == _hosts.end()) {
        _confMutex.unlock();
        return false;
    }
    _confMutex.unlock();
    return nextHost(host, port);
}

bool UDPConfiguration::nextHost(QString& host, int& port)
{
    QMutexLocker locker(&_confMutex);
    if(_it != _hosts.end()) {
        host = _it.key();
        port = _it.value();
        _it++;
        return true;
    }
    return false;
}

void UDPConfiguration::setLocalPort(quint16 port)
{
    _localPort = port;
}

void UDPConfiguration::saveSettings(QSettings& settings, const QString& root)
{
    _confMutex.lock();
    settings.beginGroup(root);
    settings.setValue("port", (int)_localPort);
    settings.setValue("hostCount", _hosts.count());
    int index = 0;
    QMap<QString, int>::const_iterator it = _hosts.begin();
    while(it != _hosts.end()) {
        QString hkey = QString("host%1").arg(index);
        settings.setValue(hkey, it.key());
        QString pkey = QString("port%1").arg(index);
        settings.setValue(pkey, it.value());
        it++;
        index++;
    }
    settings.endGroup();
    _confMutex.unlock();
}

void UDPConfiguration::loadSettings(QSettings& settings, const QString& root)
{
    _confMutex.lock();
    _hosts.clear();
    _confMutex.unlock();
    settings.beginGroup(root);
    _localPort = (quint16)settings.value("port", QGC_UDP_LOCAL_PORT).toUInt();
    int hostCount = settings.value("hostCount", 0).toInt();
    for(int i = 0; i < hostCount; i++) {
        QString hkey = QString("host%1").arg(i);
        QString pkey = QString("port%1").arg(i);
        if(settings.contains(hkey) && settings.contains(pkey)) {
            addHost(settings.value(hkey).toString(), settings.value(pkey).toInt());
        }
    }
    settings.endGroup();
    _updateHostList();
}

void UDPConfiguration::updateSettings()
{
    if(_link) {
        UDPLink* ulink = dynamic_cast<UDPLink*>(_link);
        if(ulink) {
            ulink->_restartConnection();
        }
    }
}

void UDPConfiguration::_updateHostList()
{
    _hostList.clear();
    QMap<QString, int>::const_iterator it = _hosts.begin();
    while(it != _hosts.end()) {
        QString host = QString("%1").arg(it.key()) + ":" + QString("%1").arg(it.value());
        _hostList += host;
        it++;
    }
    emit hostListChanged();
}
<commit_msg>Better error output<commit_after>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

/**
 * @file
 *   @brief Definition of UDP connection (server) for unmanned vehicles
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QtGlobal>
#include <QTimer>
#include <QList>
#include <QDebug>
#include <QMutexLocker>
#include <QNetworkProxy>
#include <QNetworkInterface>
#include <iostream>

#include "UDPLink.h"
#include "QGC.h"
#include <QHostInfo>

#define REMOVE_GONE_HOSTS 0

static const char* kZeroconfRegistration = "_qgroundcontrol._udp";

static bool is_ip(const QString& address)
{
    int a,b,c,d;
    if (sscanf(address.toStdString().c_str(), "%d.%d.%d.%d", &a, &b, &c, &d) != 4
            && strcmp("::1", address.toStdString().c_str())) {
        return false;
    } else {
        return true;
    }
}

static QString get_ip_address(const QString& address)
{
    if(is_ip(address))
        return address;
    // Need to look it up
    QHostInfo info = QHostInfo::fromName(address);
    if (info.error() == QHostInfo::NoError)
    {
        QList<QHostAddress> hostAddresses = info.addresses();
        QHostAddress address;
        for (int i = 0; i < hostAddresses.size(); i++)
        {
            // Exclude all IPv6 addresses
            if (!hostAddresses.at(i).toString().contains(":"))
            {
                return hostAddresses.at(i).toString();
            }
        }
    }
    return QString("");
}

UDPLink::UDPLink(SharedLinkConfigurationPointer& config)
    : LinkInterface(config)
#if defined(QGC_ZEROCONF_ENABLED)
    , _dnssServiceRef(NULL)
#endif
    , _running(false)
    , _socket(NULL)
    , _udpConfig(qobject_cast<UDPConfiguration*>(config.data()))
    , _connectState(false)
{
    Q_ASSERT(_udpConfig);
    moveToThread(this);
}

UDPLink::~UDPLink()
{
    _disconnect();
    // Tell the thread to exit
    _running = false;
    quit();
    // Wait for it to exit
    wait();
    this->deleteLater();
}

/**
 * @brief Runs the thread
 *
 **/
void UDPLink::run()
{
    if(_hardwareConnect()) {
        exec();
    }
    if (_socket) {
        _deregisterZeroconf();
        _socket->close();
    }
}

void UDPLink::_restartConnection()
{
    if(this->isConnected())
    {
        _disconnect();
        _connect();
    }
}

QString UDPLink::getName() const
{
    return _udpConfig->name();
}

void UDPLink::addHost(const QString& host)
{
    _udpConfig->addHost(host);
}

void UDPLink::removeHost(const QString& host)
{
    _udpConfig->removeHost(host);
}

void UDPLink::_writeBytes(const QByteArray data)
{
    if (!_socket)
        return;

    QStringList goneHosts;
    // Send to all connected systems
    QString host;
    int port;
    if(_udpConfig->firstHost(host, port)) {
        do {
            QHostAddress currentHost(host);
            if(_socket->writeDatagram(data, currentHost, (quint16)port) < 0) {
                // This host is gone. Add to list to be removed
                // We should keep track of hosts that were manually added (static) and
                // hosts that were added because we heard from them (dynamic). Only
                // dynamic hosts should be removed and even then, after a few tries, not
                // the first failure. In the mean time, we don't remove anything.
                if(REMOVE_GONE_HOSTS) {
                    goneHosts.append(host);
                }
            } else {
                // Only log rate if data actually got sent. Not sure about this as
                // "host not there" takes time too regardless of size of data. In fact,
                // 1 byte or "UDP frame size" bytes are the same as that's the data
                // unit sent by UDP.
                _logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch());
            }
        } while (_udpConfig->nextHost(host, port));
        //-- Remove hosts that are no longer there
        foreach (const QString& ghost, goneHosts) {
            _udpConfig->removeHost(ghost);
        }
    }
}

/**
 * @brief Read a number of bytes from the interface.
 **/
void UDPLink::readBytes()
{
    QByteArray databuffer;
    while (_socket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(_socket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        _socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        databuffer.append(datagram);
        //-- Wait a bit before sending it over
        if(databuffer.size() > 10 * 1024) {
            emit bytesReceived(this, databuffer);
            databuffer.clear();
        }
        _logInputDataRate(datagram.length(), QDateTime::currentMSecsSinceEpoch());
        // TODO This doesn't validade the sender. Anything sending UDP packets to this port gets
        // added to the list and will start receiving datagrams from here. Even a port scanner
        // would trigger this.
        // Add host to broadcast list if not yet present, or update its port
        _udpConfig->addHost(sender.toString(), (int)senderPort);
    }
    //-- Send whatever is left
    if(databuffer.size()) {
        emit bytesReceived(this, databuffer);
    }
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
void UDPLink::_disconnect(void)
{
    _running = false;
    quit();
    wait();
    if (_socket) {
        // Make sure delete happen on correct thread
        _socket->deleteLater();
        _socket = NULL;
        emit disconnected();
    }
    _connectState = false;
}

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
bool UDPLink::_connect(void)
{
    if(this->isRunning() || _running)
    {
        _running = false;
        quit();
        wait();
    }
    _running = true;
    start(NormalPriority);
    return true;
}

bool UDPLink::_hardwareConnect()
{
    if (_socket) {
        delete _socket;
        _socket = NULL;
    }
    QHostAddress host = QHostAddress::AnyIPv4;
    _socket = new QUdpSocket();
    _socket->setProxy(QNetworkProxy::NoProxy);
    _connectState = _socket->bind(host, _udpConfig->localPort(), QAbstractSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
    if (_connectState) {
        //-- Make sure we have a large enough IO buffers
#ifdef __mobile__
        _socket->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption,     64 * 1024);
        _socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 128 * 1024);
#else
        _socket->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption,    256 * 1024);
        _socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 512 * 1024);
#endif
        _registerZeroconf(_udpConfig->localPort(), kZeroconfRegistration);
        QObject::connect(_socket, &QUdpSocket::readyRead, this, &UDPLink::readBytes);
        emit connected();
    } else {
        emit communicationError(tr("UDP Link Error"), tr("Error binding UDP port: %1").arg(_socket->errorString()));
    }
    return _connectState;
}

/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
bool UDPLink::isConnected() const
{
    return _connectState;
}

qint64 UDPLink::getConnectionSpeed() const
{
    return 54000000; // 54 Mbit
}

qint64 UDPLink::getCurrentInDataRate() const
{
    return 0;
}

qint64 UDPLink::getCurrentOutDataRate() const
{
    return 0;
}

void UDPLink::_registerZeroconf(uint16_t port, const std::string &regType)
{
#if defined(QGC_ZEROCONF_ENABLED)
    DNSServiceErrorType result = DNSServiceRegister(&_dnssServiceRef, 0, 0, 0,
        regType.c_str(),
        NULL,
        NULL,
        htons(port),
        0,
        NULL,
        NULL,
        NULL);
    if (result != kDNSServiceErr_NoError)
    {
        emit communicationError("UDP Link Error", "Error registering Zeroconf");
        _dnssServiceRef = NULL;
    }
#else
    Q_UNUSED(port);
    Q_UNUSED(regType);
#endif
}

void UDPLink::_deregisterZeroconf()
{
#if defined(QGC_ZEROCONF_ENABLED)
    if (_dnssServiceRef)
     {
         DNSServiceRefDeallocate(_dnssServiceRef);
         _dnssServiceRef = NULL;
     }
#endif
}

//--------------------------------------------------------------------------
//-- UDPConfiguration

UDPConfiguration::UDPConfiguration(const QString& name) : LinkConfiguration(name)
{
    _localPort = QGC_UDP_LOCAL_PORT;
}

UDPConfiguration::UDPConfiguration(UDPConfiguration* source) : LinkConfiguration(source)
{
    _localPort = source->localPort();
    QString host;
    int port;
    _hostList.clear();
    if(source->firstHost(host, port)) {
        do {
            addHost(host, port);
        } while(source->nextHost(host, port));
    }
}

void UDPConfiguration::copyFrom(LinkConfiguration *source)
{
    LinkConfiguration::copyFrom(source);
    UDPConfiguration* usource = dynamic_cast<UDPConfiguration*>(source);
    Q_ASSERT(usource != NULL);
    _localPort = usource->localPort();
    _hosts.clear();
    QString host;
    int port;
    if(usource->firstHost(host, port)) {
        do {
            addHost(host, port);
        } while(usource->nextHost(host, port));
    }
}

/**
 * @param host Hostname in standard formatt, e.g. localhost:14551 or 192.168.1.1:14551
 */
void UDPConfiguration::addHost(const QString host)
{
    // Handle x.x.x.x:p
    if (host.contains(":"))
    {
        addHost(host.split(":").first(), host.split(":").last().toInt());
    }
    // If no port, use default
    else
    {
        addHost(host, (int)_localPort);
    }
}

void UDPConfiguration::addHost(const QString& host, int port)
{
    bool changed = false;
    QMutexLocker locker(&_confMutex);
    if(_hosts.contains(host)) {
        if(_hosts[host] != port) {
            _hosts[host] = port;
            changed = true;
        }
    } else {
        QString ipAdd = get_ip_address(host);
        if(ipAdd.isEmpty()) {
            qWarning() << "UDP:" << "Could not resolve host:" << host << "port:" << port;
        } else {
            // In simulation and testing setups the vehicle and the GCS can be
            // running on the same host. This leads to packets arriving through
            // the local network or the loopback adapter, which makes it look
            // like the vehicle is connected through two different links,
            // complicating routing.
            //
            // We detect this case and force all traffic to a simulated instance
            // onto the local loopback interface.
            bool not_local = true;
            // Run through all IPv4 interfaces and check if their canonical
            // IP address in string representation matches the source IP address
            foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {
                if (address.protocol() == QAbstractSocket::IPv4Protocol) {
                    if (ipAdd.endsWith(address.toString())) {
                        // This is a local address of the same host
                        not_local = false;
                    }
                }
            }
            if (not_local) {
                // This is a normal remote host, add it using its IPv4 address
                _hosts[ipAdd] = port;
                //qDebug() << "UDP:" << "Adding Host:" << ipAdd << ":" << port;
            } else {
                // It is localhost, so talk to it through the IPv4 loopback interface
                _hosts["127.0.0.1"] = port;
            }
            changed = true;
        }
    }
    if(changed) {
        _updateHostList();
    }
}

void UDPConfiguration::removeHost(const QString host)
{
    QMutexLocker locker(&_confMutex);
    QString tHost = host;
    if (tHost.contains(":")) {
        tHost = tHost.split(":").first();
    }
    tHost = tHost.trimmed();
    QMap<QString, int>::iterator i = _hosts.find(tHost);
    if(i != _hosts.end()) {
        //qDebug() << "UDP:" << "Removed host:" << host;
        _hosts.erase(i);
    } else {
        qWarning() << "UDP:" << "Could not remove unknown host:" << host;
    }
    _updateHostList();
}

bool UDPConfiguration::firstHost(QString& host, int& port)
{
    _confMutex.lock();
    _it = _hosts.begin();
    if(_it == _hosts.end()) {
        _confMutex.unlock();
        return false;
    }
    _confMutex.unlock();
    return nextHost(host, port);
}

bool UDPConfiguration::nextHost(QString& host, int& port)
{
    QMutexLocker locker(&_confMutex);
    if(_it != _hosts.end()) {
        host = _it.key();
        port = _it.value();
        _it++;
        return true;
    }
    return false;
}

void UDPConfiguration::setLocalPort(quint16 port)
{
    _localPort = port;
}

void UDPConfiguration::saveSettings(QSettings& settings, const QString& root)
{
    _confMutex.lock();
    settings.beginGroup(root);
    settings.setValue("port", (int)_localPort);
    settings.setValue("hostCount", _hosts.count());
    int index = 0;
    QMap<QString, int>::const_iterator it = _hosts.begin();
    while(it != _hosts.end()) {
        QString hkey = QString("host%1").arg(index);
        settings.setValue(hkey, it.key());
        QString pkey = QString("port%1").arg(index);
        settings.setValue(pkey, it.value());
        it++;
        index++;
    }
    settings.endGroup();
    _confMutex.unlock();
}

void UDPConfiguration::loadSettings(QSettings& settings, const QString& root)
{
    _confMutex.lock();
    _hosts.clear();
    _confMutex.unlock();
    settings.beginGroup(root);
    _localPort = (quint16)settings.value("port", QGC_UDP_LOCAL_PORT).toUInt();
    int hostCount = settings.value("hostCount", 0).toInt();
    for(int i = 0; i < hostCount; i++) {
        QString hkey = QString("host%1").arg(i);
        QString pkey = QString("port%1").arg(i);
        if(settings.contains(hkey) && settings.contains(pkey)) {
            addHost(settings.value(hkey).toString(), settings.value(pkey).toInt());
        }
    }
    settings.endGroup();
    _updateHostList();
}

void UDPConfiguration::updateSettings()
{
    if(_link) {
        UDPLink* ulink = dynamic_cast<UDPLink*>(_link);
        if(ulink) {
            ulink->_restartConnection();
        }
    }
}

void UDPConfiguration::_updateHostList()
{
    _hostList.clear();
    QMap<QString, int>::const_iterator it = _hosts.begin();
    while(it != _hosts.end()) {
        QString host = QString("%1").arg(it.key()) + ":" + QString("%1").arg(it.value());
        _hostList += host;
        it++;
    }
    emit hostListChanged();
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <algorithm>
#include <stdio.h>
#include <ctype.h>

#include "conf.hh"
#include "globals.hh"
#include "consumer.hh"
#include "env.hh"

using namespace std;
using namespace boost::filesystem;

int find_feat(string::iterator bstring, string::iterator estring) {
    // bounds check for ft./Ft.
    if (bstring + 2 >= estring) {
        return 0;
    }
    if (bstring[0] == 'f' || bstring[0] == 'F') {
        if (bstring[1] == 't' && bstring[2] == '.') {
            return 3;
        }

        // bounds check for feat./Feat.
        if (bstring + 4 >= estring) {
            return 0;
        }
        if (bstring[1] == 'e' && bstring[2] == 'a' &&
            bstring[3] == 't' && bstring[4] == '.') {
            return 5;
        }
    }
    return 0;
}

string fix_feat_delim(const string::iterator bstring,
                      const string::iterator estring,
                      const char odelim, const char cdelim) {
    auto istring = find(bstring, estring, odelim);
    if (istring == estring || /* !!! */ ++istring == estring) {
        return {bstring, estring};
    }

    // istring is now after the [
    if (auto feat_offset = find_feat(istring, estring)) {
        auto ebracket = find(istring, estring, cdelim);
        if (ebracket == estring) {
            return {};
        }
        string output{bstring, istring - 1};
        output += '(';
        output.append("feat.");
        output.append(istring + feat_offset, ebracket);
        output += ')';
        if (ebracket + 1 != estring) {
            output.append(ebracket + 1, estring);
        }
        return output;
    }
    return {bstring, estring};
}

string
fix_feat_nodelim(string::iterator bstring, string::iterator estring) {
    auto istring = bstring;
    while (istring != estring) {
        istring = find_if(istring, estring, [](char ch) {
            return ch == 'f' || ch == 'F';
        });
        if (istring - 1 != bstring && istring[-1] == '(') {
            ++istring;
            continue;
        }
        if (istring == estring) {
            break;
        }
        if (auto feat_offset = find_feat(istring, estring)) {
            string output{bstring, istring};
            output += "(feat.";

            // if has (for example) a `(SXX Remix)`
            auto efeat = find(istring + feat_offset, estring, '(');
            while (isspace(*--efeat)) {
            }
            ++efeat;

            output.append(istring + feat_offset, efeat);
            output += ')';
            if (efeat != estring) {
                output.append(efeat, estring);
            }
            return output;
        }
        ++istring;
    }
    return {bstring, estring};
}

/// Change featuring info to the way I want:
/// Words:
/// `ft.`, `Ft.`, `Feat.` --> feat.
/// Delimiter:
/// None, `[` then `]` --> `(` then `)`
static string
fix_feat(string::iterator istring, string::iterator estring) {
    auto fbrackets = fix_feat_delim(istring, estring, '[', ']');
    auto fparens =
        fix_feat_delim(fbrackets.begin(), fbrackets.end(), '(', ')');
    auto fnone = fix_feat_nodelim(fparens.begin(), fparens.end());
    return fnone;
}

/// Remove `\[.*?\] ` and an optional `- ` from the beginning.
void remove_genre(string::iterator& istring,
                  const string::iterator& estring) {
    if (*istring == '[') {
        do {
            istring = find(istring, estring, ']');
            if (istring == estring) {
                fprintf(stderr,
                        "Unmatched `[`.  Skipping removing genre.\n");
                break;
            }
            if (istring[1] == ' ') {
                istring += 2;
                if (istring[0] == '-' && istring[1] == ' ') {
                    istring += 2;
                }
            }
        } while (0);
    }
}

/// Remove `\s*\[.*?\]` from end if it exists.
static void remove_trailing_tags(const string& no_slashes,
                                 string::iterator& istring,
                                 string::iterator& estring) {
    do {
        auto rbstring = no_slashes.rbegin();
        auto ristring = rbstring;
        auto restring = rbstring + (estring - istring);

        if (ristring != restring && *ristring == ']') {
            ristring = find(ristring, restring, '[');
            if (ristring == restring) {
                fprintf(stderr, "Unmatched `]`.  Skipping remove "
                                "trailing tags.\n");
                break;
            }

            // check for feat, skip if is
            auto iter = ristring;
            --iter;
            if (*iter == 'f' || *iter == 'F') {
                --iter;
                if (*iter == 't') {
                    --iter;
                    if (*iter == '.') {
                        break;
                    }
                } else if (*iter == 'e') {
                    --iter;
                    if (*iter == 'a') {
                        --iter;
                        if (*iter == 't') {
                            --iter;
                            if (*iter == '.') {
                                break;
                            }
                        }
                    }
                }
            }

            ++ristring;
            if (ristring == restring) {
                fprintf(stderr, "Trailing tags are entire filename.  "
                                "Skipping remove trailing tags.\n");
                break;
            }

            // skip whitespace
            ristring =
                find_if(ristring, restring,
                        [](char ch) -> bool { return !isspace(ch); });
            if (ristring == restring) {
                fprintf(stderr, "Trailing tags are entire filename.  "
                                "Skipping remove trailing tags.\n");
                break;
            }

            // commit ristring to estring
            estring = estring - (ristring - rbstring);
        }
    } while (0);
}

/// Split `fname` into `artist\s+-\s*name`
static void
parse_file_name(const string& fname, string& artist, string& name) {
    const auto bfname = fname.begin();
    const auto efname = fname.end();

    auto dash_loc = bfname;
restart:
    dash_loc = find(dash_loc, efname, '-');

    /* artist */ {
        auto eartist = dash_loc;
        bool went_through_space = false;
        // backtrack through whitespace
        while (isspace(*--eartist)) {
            went_through_space = true;
        }
        ++eartist;
        // handle the case where name has a -
        if (!went_through_space) {
            ++dash_loc;
            goto restart;
        }
        artist.assign(bfname, eartist);
    }

    /* name */ {
        auto bname = dash_loc;
        // go forward through whitespace
        while (isspace(*++bname)) {
        }
        name.assign(bname, efname);
    }
}

void Consumer::consume(const path& p) {
    // dropped .mp3 here
    auto no_slashes = p.filename().replace_extension().string();

    auto bstring = no_slashes.begin();
    auto estring = no_slashes.end();
    auto istring = bstring;

    remove_genre(istring, estring);
    remove_trailing_tags(no_slashes, istring, estring);
    auto new_fname = fix_feat(istring, estring);

    auto new_path = get_songs_dir() / (new_fname + ".mp3");

    _sorted_insert_song_(new_path.filename().string());
    if (p != new_path) {
        if (NONO) {
            printf("mv \"%s\" \"%s\"\n", p.c_str(), new_path.c_str());
        } else {
            rename(p, new_path);
        }
    }

    string artist, name;
    parse_file_name(new_fname, artist, name);

    if (NONO) {
        _apply_tags_(p, artist, name);
    } else {
        _apply_tags_(new_path, artist, name);
    }
}
<commit_msg>In consume_path.cc, make local functions static<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <algorithm>
#include <stdio.h>
#include <ctype.h>

#include "conf.hh"
#include "globals.hh"
#include "consumer.hh"
#include "env.hh"

using namespace std;
using namespace boost::filesystem;

static int find_feat(string::iterator bstring, string::iterator estring) {
    // bounds check for ft./Ft.
    if (bstring + 2 >= estring) {
        return 0;
    }
    if (bstring[0] == 'f' || bstring[0] == 'F') {
        if (bstring[1] == 't' && bstring[2] == '.') {
            return 3;
        }

        // bounds check for feat./Feat.
        if (bstring + 4 >= estring) {
            return 0;
        }
        if (bstring[1] == 'e' && bstring[2] == 'a' &&
            bstring[3] == 't' && bstring[4] == '.') {
            return 5;
        }
    }
    return 0;
}

static string fix_feat_delim(const string::iterator bstring,
                      const string::iterator estring,
                      const char odelim, const char cdelim) {
    auto istring = find(bstring, estring, odelim);
    if (istring == estring || /* !!! */ ++istring == estring) {
        return {bstring, estring};
    }

    // istring is now after the [
    if (auto feat_offset = find_feat(istring, estring)) {
        auto ebracket = find(istring, estring, cdelim);
        if (ebracket == estring) {
            return {};
        }
        string output{bstring, istring - 1};
        output += '(';
        output.append("feat.");
        output.append(istring + feat_offset, ebracket);
        output += ')';
        if (ebracket + 1 != estring) {
            output.append(ebracket + 1, estring);
        }
        return output;
    }
    return {bstring, estring};
}

static string
fix_feat_nodelim(string::iterator bstring, string::iterator estring) {
    auto istring = bstring;
    while (istring != estring) {
        istring = find_if(istring, estring, [](char ch) {
            return ch == 'f' || ch == 'F';
        });
        if (istring - 1 != bstring && istring[-1] == '(') {
            ++istring;
            continue;
        }
        if (istring == estring) {
            break;
        }
        if (auto feat_offset = find_feat(istring, estring)) {
            string output{bstring, istring};
            output += "(feat.";

            // if has (for example) a `(SXX Remix)`
            auto efeat = find(istring + feat_offset, estring, '(');
            while (isspace(*--efeat)) {
            }
            ++efeat;

            output.append(istring + feat_offset, efeat);
            output += ')';
            if (efeat != estring) {
                output.append(efeat, estring);
            }
            return output;
        }
        ++istring;
    }
    return {bstring, estring};
}

/// Change featuring info to the way I want:
/// Words:
/// `ft.`, `Ft.`, `Feat.` --> feat.
/// Delimiter:
/// None, `[` then `]` --> `(` then `)`
static string
fix_feat(string::iterator istring, string::iterator estring) {
    auto fbrackets = fix_feat_delim(istring, estring, '[', ']');
    auto fparens =
        fix_feat_delim(fbrackets.begin(), fbrackets.end(), '(', ')');
    auto fnone = fix_feat_nodelim(fparens.begin(), fparens.end());
    return fnone;
}

/// Remove `\[.*?\] ` and an optional `- ` from the beginning.
static void remove_genre(string::iterator& istring,
                  const string::iterator& estring) {
    if (*istring == '[') {
        do {
            istring = find(istring, estring, ']');
            if (istring == estring) {
                fprintf(stderr,
                        "Unmatched `[`.  Skipping removing genre.\n");
                break;
            }
            if (istring[1] == ' ') {
                istring += 2;
                if (istring[0] == '-' && istring[1] == ' ') {
                    istring += 2;
                }
            }
        } while (0);
    }
}

/// Remove `\s*\[.*?\]` from end if it exists.
static void remove_trailing_tags(const string& no_slashes,
                                 string::iterator& istring,
                                 string::iterator& estring) {
    do {
        auto rbstring = no_slashes.rbegin();
        auto ristring = rbstring;
        auto restring = rbstring + (estring - istring);

        if (ristring != restring && *ristring == ']') {
            ristring = find(ristring, restring, '[');
            if (ristring == restring) {
                fprintf(stderr, "Unmatched `]`.  Skipping remove "
                                "trailing tags.\n");
                break;
            }

            // check for feat, skip if is
            auto iter = ristring;
            --iter;
            if (*iter == 'f' || *iter == 'F') {
                --iter;
                if (*iter == 't') {
                    --iter;
                    if (*iter == '.') {
                        break;
                    }
                } else if (*iter == 'e') {
                    --iter;
                    if (*iter == 'a') {
                        --iter;
                        if (*iter == 't') {
                            --iter;
                            if (*iter == '.') {
                                break;
                            }
                        }
                    }
                }
            }

            ++ristring;
            if (ristring == restring) {
                fprintf(stderr, "Trailing tags are entire filename.  "
                                "Skipping remove trailing tags.\n");
                break;
            }

            // skip whitespace
            ristring =
                find_if(ristring, restring,
                        [](char ch) -> bool { return !isspace(ch); });
            if (ristring == restring) {
                fprintf(stderr, "Trailing tags are entire filename.  "
                                "Skipping remove trailing tags.\n");
                break;
            }

            // commit ristring to estring
            estring = estring - (ristring - rbstring);
        }
    } while (0);
}

/// Split `fname` into `artist\s+-\s*name`
static void
parse_file_name(const string& fname, string& artist, string& name) {
    const auto bfname = fname.begin();
    const auto efname = fname.end();

    auto dash_loc = bfname;
restart:
    dash_loc = find(dash_loc, efname, '-');

    /* artist */ {
        auto eartist = dash_loc;
        bool went_through_space = false;
        // backtrack through whitespace
        while (isspace(*--eartist)) {
            went_through_space = true;
        }
        ++eartist;
        // handle the case where name has a -
        if (!went_through_space) {
            ++dash_loc;
            goto restart;
        }
        artist.assign(bfname, eartist);
    }

    /* name */ {
        auto bname = dash_loc;
        // go forward through whitespace
        while (isspace(*++bname)) {
        }
        name.assign(bname, efname);
    }
}

void Consumer::consume(const path& p) {
    // dropped .mp3 here
    auto no_slashes = p.filename().replace_extension().string();

    auto bstring = no_slashes.begin();
    auto estring = no_slashes.end();
    auto istring = bstring;

    remove_genre(istring, estring);
    remove_trailing_tags(no_slashes, istring, estring);
    auto new_fname = fix_feat(istring, estring);

    auto new_path = get_songs_dir() / (new_fname + ".mp3");

    _sorted_insert_song_(new_path.filename().string());
    if (p != new_path) {
        if (NONO) {
            printf("mv \"%s\" \"%s\"\n", p.c_str(), new_path.c_str());
        } else {
            rename(p, new_path);
        }
    }

    string artist, name;
    parse_file_name(new_fname, artist, name);

    if (NONO) {
        _apply_tags_(p, artist, name);
    } else {
        _apply_tags_(new_path, artist, name);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Google Inc. All rights reserved.
//
// 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.
//
// PKCS#11 s11.14: Key management functions
//   C_GenerateKey
//   C_GenerateKeyPair
//   C_WrapKey
//   C_UnwrapKey
//   C_DeriveKey
#include "pkcs11test.h"

using namespace std;  // So sue me

namespace pkcs11 {
namespace test {

TEST_F(ReadOnlySessionTest, GenerateKeyInvalid) {
  CK_MECHANISM mechanism = {CKM_DES_KEY_GEN, NULL_PTR, 0};
  CK_ATTRIBUTE attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  CK_OBJECT_HANDLE key;
  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
             g_fns->C_GenerateKey(INVALID_SESSION_HANDLE, &mechanism, attrs, 3, &key));
  CK_RV rv = g_fns->C_GenerateKey(session_, NULL_PTR, attrs, 3, &key);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKey(session_, &mechanism, NULL_PTR, 3, &key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKey(session_, &mechanism, attrs, 3, NULL_PTR));

}

TEST_F(ReadOnlySessionTest, GenerateKeyPairInvalid) {
  CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
  CK_ULONG modulus_bits = 1024;
  CK_BYTE public_exponent_value[] = {0x1, 0x0, 0x1}; // 65537=0x010001
  CK_ATTRIBUTE public_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
    {CKA_PUBLIC_EXPONENT, public_exponent_value, sizeof(public_exponent_value)},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  CK_ATTRIBUTE private_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  CK_OBJECT_HANDLE public_key;
  CK_OBJECT_HANDLE private_key;

  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
    g_fns->C_GenerateKeyPair(INVALID_SESSION_HANDLE, &mechanism,
                             public_attrs, 4,
                             private_attrs, 2,
                             &public_key, &private_key));
  CK_RV rv = g_fns->C_GenerateKeyPair(session_, NULL_PTR,
                                      public_attrs, 4,
                                      private_attrs, 2,
                                      &public_key, &private_key);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      NULL_PTR, 4,
                                      private_attrs, 2,
                                      &public_key, &private_key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 4,
                                      NULL_PTR, 2,
                                      &public_key, &private_key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 4,
                                      private_attrs, 2,
                                      NULL_PTR, &private_key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 4,
                                      private_attrs, 2,
                                      &public_key, NULL_PTR));
}

TEST_F(ReadOnlySessionTest, WrapUnwrap) {
  ObjectAttributes k1_attrs = ObjectAttributes();
  CK_ATTRIBUTE insensitive_attr = {CKA_SENSITIVE, &g_ck_false, sizeof(g_ck_false)};
  k1_attrs.push_back(insensitive_attr);
  SecretKey k1(session_, k1_attrs);

  vector<CK_ATTRIBUTE_TYPE> k2_attrs = {CKA_WRAP, CKA_UNWRAP, CKA_DECRYPT};
  SecretKey k2(session_, k2_attrs);

  // Use k2 to wrap k1.
  CK_MECHANISM wrap_mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  CK_BYTE data[4096];
  CK_ULONG data_len = sizeof(data);
  CK_RV rv = g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    TEST_SKIPPED("Key wrapping not supported");
    return;
  }
  EXPECT_CKR_OK(rv);

  // Use k2 to decrypt the result, giving contents of k1.
  EXPECT_CKR_OK(g_fns->C_DecryptInit(session_, &wrap_mechanism, k2.handle()));
  CK_BYTE key[4096];
  CK_ULONG key_out_len = sizeof(key);
  EXPECT_CKR_OK(g_fns->C_Decrypt(session_, data, data_len, key, &key_out_len));

  CK_BYTE k1_value[2048];
  CK_ATTRIBUTE get_attr = {CKA_VALUE, k1_value, sizeof(k1_value)};
  EXPECT_CKR_OK(g_fns->C_GetAttributeValue(session_, k1.handle(), &get_attr, 1));
  CK_ULONG k1_len = get_attr.ulValueLen;

  EXPECT_EQ(k1_len, key_out_len);
  EXPECT_EQ(hex_data(k1_value, k1_len), hex_data(key, key_out_len));

  // Unwrap to generate a key object with the same value.
  CK_OBJECT_HANDLE k3;
  CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
  CK_KEY_TYPE key_type = CKK_DES;
  CK_ATTRIBUTE k3_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_CLASS, &key_class, sizeof(key_class)},
    {CKA_KEY_TYPE, (CK_VOID_PTR)&key_type, sizeof(key_type)},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  EXPECT_CKR_OK(g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), data, data_len, k3_attrs, 5, &k3));

  CK_BYTE k3_value[2048];
  CK_ATTRIBUTE k3_get_attr = {CKA_VALUE, k3_value, sizeof(k3_value)};
  EXPECT_CKR_OK(g_fns->C_GetAttributeValue(session_, k3, &k3_get_attr, 1));
  CK_ULONG k3_len = get_attr.ulValueLen;
  EXPECT_EQ(hex_data(k1_value, k1_len), hex_data(k3_value, k3_len));

  g_fns->C_DestroyObject(session_, k3);
}

TEST_F(ReadOnlySessionTest, WrapInvalid) {
  ObjectAttributes k1_attrs = ObjectAttributes();
  CK_ATTRIBUTE insensitive_attr = {CKA_SENSITIVE, &g_ck_false, sizeof(g_ck_false)};
  k1_attrs.push_back(insensitive_attr);
  SecretKey k1(session_, k1_attrs);

  vector<CK_ATTRIBUTE_TYPE> k2_attrs = {CKA_WRAP, CKA_UNWRAP, CKA_DECRYPT};
  SecretKey k2(session_, k2_attrs);

  // Use k2 to wrap k1.
  CK_MECHANISM wrap_mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  CK_BYTE data[4096];
  CK_ULONG data_len = sizeof(data);

  CK_RV rv = g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    TEST_SKIPPED("Key wrapping not supported");
    return;
  }
  EXPECT_CKR_OK(rv);

  data_len = sizeof(data);
  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
             g_fns->C_WrapKey(INVALID_SESSION_HANDLE, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len));
  rv = g_fns->C_WrapKey(session_, NULL_PTR, k2.handle(), k1.handle(), data, &data_len);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_WRAPPING_KEY_HANDLE_INVALID,
             g_fns->C_WrapKey(session_, &wrap_mechanism, INVALID_OBJECT_HANDLE, k1.handle(), data, &data_len));
  EXPECT_CKR(CKR_KEY_HANDLE_INVALID,
             g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), INVALID_OBJECT_HANDLE, data, &data_len));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, NULL_PTR));

  // Too-small output cases.
  EXPECT_CKR_OK(g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), NULL_PTR, &data_len));
  data_len = 1;
  EXPECT_CKR(CKR_BUFFER_TOO_SMALL,
             g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len));
}

TEST_F(ReadOnlySessionTest, UnwrapInvalid) {
  ObjectAttributes k1_attrs = ObjectAttributes();
  CK_ATTRIBUTE insensitive_attr = {CKA_SENSITIVE, &g_ck_false, sizeof(g_ck_false)};
  k1_attrs.push_back(insensitive_attr);
  SecretKey k1(session_, k1_attrs);

  vector<CK_ATTRIBUTE_TYPE> k2_attrs = {CKA_WRAP, CKA_UNWRAP, CKA_DECRYPT};
  SecretKey k2(session_, k2_attrs);

  // Use k2 to wrap k1.
  CK_MECHANISM wrap_mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  CK_BYTE data[4096];
  CK_ULONG data_len = sizeof(data);

  CK_RV rv = g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    // Assume implementation is symmetric w.r.t. Wrap/Unwrap.
    TEST_SKIPPED("Key wrapping not supported");
    return;
  }
  EXPECT_CKR_OK(rv);

  CK_OBJECT_HANDLE k3 = 0;
  CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
  CK_KEY_TYPE key_type = CKK_DES;
  CK_ATTRIBUTE k3_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_CLASS, &key_class, sizeof(key_class)},
    {CKA_KEY_TYPE, (CK_VOID_PTR)&key_type, sizeof(key_type)},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };

  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
             g_fns->C_UnwrapKey(INVALID_SESSION_HANDLE, &wrap_mechanism, k2.handle(), data, data_len, k3_attrs, 5, &k3));
  rv = g_fns->C_UnwrapKey(session_, NULL_PTR, k2.handle(), data, data_len, k3_attrs, 5, &k3);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_WRAPPING_KEY_HANDLE_INVALID,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, NULL_PTR, data, data_len, k3_attrs, 5, &k3));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), NULL_PTR, data_len, k3_attrs, 5, &k3));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), data, data_len, NULL_PTR, 5, &k3));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), data, data_len, k3_attrs, 5, NULL_PTR));

  g_fns->C_DestroyObject(session_, k3);  // In case of accidental creation
}

}  // namespace test
}  // namespace pkcs11
<commit_msg>Expect CKR_UNWRAPPING_KEY_HANDLE_INVALID for C_UnwrapKey (#23)<commit_after>// Copyright 2013-2014 Google Inc. All rights reserved.
//
// 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.
//
// PKCS#11 s11.14: Key management functions
//   C_GenerateKey
//   C_GenerateKeyPair
//   C_WrapKey
//   C_UnwrapKey
//   C_DeriveKey
#include "pkcs11test.h"

using namespace std;  // So sue me

namespace pkcs11 {
namespace test {

TEST_F(ReadOnlySessionTest, GenerateKeyInvalid) {
  CK_MECHANISM mechanism = {CKM_DES_KEY_GEN, NULL_PTR, 0};
  CK_ATTRIBUTE attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  CK_OBJECT_HANDLE key;
  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
             g_fns->C_GenerateKey(INVALID_SESSION_HANDLE, &mechanism, attrs, 3, &key));
  CK_RV rv = g_fns->C_GenerateKey(session_, NULL_PTR, attrs, 3, &key);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKey(session_, &mechanism, NULL_PTR, 3, &key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKey(session_, &mechanism, attrs, 3, NULL_PTR));

}

TEST_F(ReadOnlySessionTest, GenerateKeyPairInvalid) {
  CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
  CK_ULONG modulus_bits = 1024;
  CK_BYTE public_exponent_value[] = {0x1, 0x0, 0x1}; // 65537=0x010001
  CK_ATTRIBUTE public_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
    {CKA_PUBLIC_EXPONENT, public_exponent_value, sizeof(public_exponent_value)},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  CK_ATTRIBUTE private_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  CK_OBJECT_HANDLE public_key;
  CK_OBJECT_HANDLE private_key;

  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
    g_fns->C_GenerateKeyPair(INVALID_SESSION_HANDLE, &mechanism,
                             public_attrs, 4,
                             private_attrs, 2,
                             &public_key, &private_key));
  CK_RV rv = g_fns->C_GenerateKeyPair(session_, NULL_PTR,
                                      public_attrs, 4,
                                      private_attrs, 2,
                                      &public_key, &private_key);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      NULL_PTR, 4,
                                      private_attrs, 2,
                                      &public_key, &private_key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 4,
                                      NULL_PTR, 2,
                                      &public_key, &private_key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 4,
                                      private_attrs, 2,
                                      NULL_PTR, &private_key));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 4,
                                      private_attrs, 2,
                                      &public_key, NULL_PTR));
}

TEST_F(ReadOnlySessionTest, WrapUnwrap) {
  ObjectAttributes k1_attrs = ObjectAttributes();
  CK_ATTRIBUTE insensitive_attr = {CKA_SENSITIVE, &g_ck_false, sizeof(g_ck_false)};
  k1_attrs.push_back(insensitive_attr);
  SecretKey k1(session_, k1_attrs);

  vector<CK_ATTRIBUTE_TYPE> k2_attrs = {CKA_WRAP, CKA_UNWRAP, CKA_DECRYPT};
  SecretKey k2(session_, k2_attrs);

  // Use k2 to wrap k1.
  CK_MECHANISM wrap_mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  CK_BYTE data[4096];
  CK_ULONG data_len = sizeof(data);
  CK_RV rv = g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    TEST_SKIPPED("Key wrapping not supported");
    return;
  }
  EXPECT_CKR_OK(rv);

  // Use k2 to decrypt the result, giving contents of k1.
  EXPECT_CKR_OK(g_fns->C_DecryptInit(session_, &wrap_mechanism, k2.handle()));
  CK_BYTE key[4096];
  CK_ULONG key_out_len = sizeof(key);
  EXPECT_CKR_OK(g_fns->C_Decrypt(session_, data, data_len, key, &key_out_len));

  CK_BYTE k1_value[2048];
  CK_ATTRIBUTE get_attr = {CKA_VALUE, k1_value, sizeof(k1_value)};
  EXPECT_CKR_OK(g_fns->C_GetAttributeValue(session_, k1.handle(), &get_attr, 1));
  CK_ULONG k1_len = get_attr.ulValueLen;

  EXPECT_EQ(k1_len, key_out_len);
  EXPECT_EQ(hex_data(k1_value, k1_len), hex_data(key, key_out_len));

  // Unwrap to generate a key object with the same value.
  CK_OBJECT_HANDLE k3;
  CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
  CK_KEY_TYPE key_type = CKK_DES;
  CK_ATTRIBUTE k3_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_CLASS, &key_class, sizeof(key_class)},
    {CKA_KEY_TYPE, (CK_VOID_PTR)&key_type, sizeof(key_type)},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };
  EXPECT_CKR_OK(g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), data, data_len, k3_attrs, 5, &k3));

  CK_BYTE k3_value[2048];
  CK_ATTRIBUTE k3_get_attr = {CKA_VALUE, k3_value, sizeof(k3_value)};
  EXPECT_CKR_OK(g_fns->C_GetAttributeValue(session_, k3, &k3_get_attr, 1));
  CK_ULONG k3_len = get_attr.ulValueLen;
  EXPECT_EQ(hex_data(k1_value, k1_len), hex_data(k3_value, k3_len));

  g_fns->C_DestroyObject(session_, k3);
}

TEST_F(ReadOnlySessionTest, WrapInvalid) {
  ObjectAttributes k1_attrs = ObjectAttributes();
  CK_ATTRIBUTE insensitive_attr = {CKA_SENSITIVE, &g_ck_false, sizeof(g_ck_false)};
  k1_attrs.push_back(insensitive_attr);
  SecretKey k1(session_, k1_attrs);

  vector<CK_ATTRIBUTE_TYPE> k2_attrs = {CKA_WRAP, CKA_UNWRAP, CKA_DECRYPT};
  SecretKey k2(session_, k2_attrs);

  // Use k2 to wrap k1.
  CK_MECHANISM wrap_mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  CK_BYTE data[4096];
  CK_ULONG data_len = sizeof(data);

  CK_RV rv = g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    TEST_SKIPPED("Key wrapping not supported");
    return;
  }
  EXPECT_CKR_OK(rv);

  data_len = sizeof(data);
  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
             g_fns->C_WrapKey(INVALID_SESSION_HANDLE, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len));
  rv = g_fns->C_WrapKey(session_, NULL_PTR, k2.handle(), k1.handle(), data, &data_len);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_WRAPPING_KEY_HANDLE_INVALID,
             g_fns->C_WrapKey(session_, &wrap_mechanism, INVALID_OBJECT_HANDLE, k1.handle(), data, &data_len));
  EXPECT_CKR(CKR_KEY_HANDLE_INVALID,
             g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), INVALID_OBJECT_HANDLE, data, &data_len));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, NULL_PTR));

  // Too-small output cases.
  EXPECT_CKR_OK(g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), NULL_PTR, &data_len));
  data_len = 1;
  EXPECT_CKR(CKR_BUFFER_TOO_SMALL,
             g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len));
}

TEST_F(ReadOnlySessionTest, UnwrapInvalid) {
  ObjectAttributes k1_attrs = ObjectAttributes();
  CK_ATTRIBUTE insensitive_attr = {CKA_SENSITIVE, &g_ck_false, sizeof(g_ck_false)};
  k1_attrs.push_back(insensitive_attr);
  SecretKey k1(session_, k1_attrs);

  vector<CK_ATTRIBUTE_TYPE> k2_attrs = {CKA_WRAP, CKA_UNWRAP, CKA_DECRYPT};
  SecretKey k2(session_, k2_attrs);

  // Use k2 to wrap k1.
  CK_MECHANISM wrap_mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  CK_BYTE data[4096];
  CK_ULONG data_len = sizeof(data);

  CK_RV rv = g_fns->C_WrapKey(session_, &wrap_mechanism, k2.handle(), k1.handle(), data, &data_len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
    // Assume implementation is symmetric w.r.t. Wrap/Unwrap.
    TEST_SKIPPED("Key wrapping not supported");
    return;
  }
  EXPECT_CKR_OK(rv);

  CK_OBJECT_HANDLE k3 = 0;
  CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
  CK_KEY_TYPE key_type = CKK_DES;
  CK_ATTRIBUTE k3_attrs[] = {
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_CLASS, &key_class, sizeof(key_class)},
    {CKA_KEY_TYPE, (CK_VOID_PTR)&key_type, sizeof(key_type)},
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
  };

  EXPECT_CKR(CKR_SESSION_HANDLE_INVALID,
             g_fns->C_UnwrapKey(INVALID_SESSION_HANDLE, &wrap_mechanism, k2.handle(), data, data_len, k3_attrs, 5, &k3));
  rv = g_fns->C_UnwrapKey(session_, NULL_PTR, k2.handle(), data, data_len, k3_attrs, 5, &k3);
  EXPECT_TRUE(rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_INVALID) << " rv=" << CK_RV_(rv);
  EXPECT_CKR(CKR_UNWRAPPING_KEY_HANDLE_INVALID,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, NULL_PTR, data, data_len, k3_attrs, 5, &k3));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), NULL_PTR, data_len, k3_attrs, 5, &k3));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), data, data_len, NULL_PTR, 5, &k3));
  EXPECT_CKR(CKR_ARGUMENTS_BAD,
             g_fns->C_UnwrapKey(session_, &wrap_mechanism, k2.handle(), data, data_len, k3_attrs, 5, NULL_PTR));

  g_fns->C_DestroyObject(session_, k3);  // In case of accidental creation
}

}  // namespace test
}  // namespace pkcs11
<|endoftext|>


<commit_before>#include "main.h"

void mainLoop()
{
  handleInput();

  glfwGetFramebufferSize(window, &width, &height);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // bottom-left: Euler Camera (float)
  drawQuarter(0, 0, width/2, height/2, rcamf);
  // bottom-right: Euler Camera (double)
  drawQuarter(width/2, 0, width/2, height/2, rcamd);

  // top-left: Quaternion Camera (float)
  drawQuarter(0, height/2, width/2, height/2, qcamf);
  // top-right: Quaternion Camera (double)
  drawQuarter(width/2, height/2, width/2, height/2, qcamd);

  double rdiff = getDifference(rcamf, rcamd);
  double qdiff = getDifference(qcamf, qcamd);

  cout.precision(15);
  cout << std::fixed << rdiff << ", " << qdiff << endl;

  /* Swap front and back buffers */
  glfwSwapBuffers(window);
  /* Poll for and process events */
  glfwPollEvents();
}

void handleInput()
{
  if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
  {
    glfwSetWindowShouldClose(window, GL_TRUE);
  }

  double x, y;
  int key;
  if (is_reading)
  {
    if (!(input_file >> mouse_ready))
    {
      glfwSetWindowShouldClose(window, GL_TRUE);
      return;
    }
    input_file >> x >> y;

    input_file >> key;
    while (key != -1)
    {
      doKeyToCameras(key);
      input_file >> key;
    }
  }
  else
  {
    glfwGetCursorPos(window, &x, &y);

    if (is_writing)
      output_file << mouse_ready << " " << x << " " << y << " ";

    for (unsigned i = 0; i < sizeof(KEYS)/sizeof(int); i++)
    {
      if (glfwGetKey(window, KEYS[i]) == GLFW_PRESS)
      {
        doKeyToCameras(KEYS[i]);

        if (is_writing)
          output_file << KEYS[i] << " ";
      }
    }

    if (is_writing)
      output_file << "-1" << endl;
  }
  mouseMoved(x, y);
}

void doKeyToCameras(int key)
{
  rcamf->doKey(key);
  rcamd->doKey(key);
  qcamf->doKey(key);
  qcamd->doKey(key);
}

void mouseCheck(GLFWwindow*,double x,double y)
{
  if (!mouse_ready)
  {
    mouse_ready = true;
    mx = x; my = y;

    if (is_writing)
      output_file << "0 " << mx << " " << my << " -1 ";
  }
}

void mouseMoved(double x, double y)
{
  if (mouse_ready)
  {
    double dx = x - mx;
    double dy = y - my;

    rcamf->mouseLook((float)dx,(float)dy);
    qcamf->mouseLook((float)dx,(float)dy);

    rcamd->mouseLook(dx,dy);
    qcamd->mouseLook(dx,dy);
  }

  mx = x; my = y;
}

void initGlfw()
{
  if (!glfwInit())
      exit(-1);

// Because Apple refuses to keep up with standards!
#ifdef __APPLE__
  glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
  glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
}

void init()
{
  initGlfw();
  initWindow();
  initGlew();

  if (!is_reading)
  {
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    glfwSetCursorPosCallback(window, mouseCheck);
  }

  glEnable(GL_VERTEX_ARRAY);
  glEnable(GL_DEPTH_TEST);
  glDisable(GL_CULL_FACE);

  glClearColor(1,1,1,1);
}

void initWindow()
{
  window = glfwCreateWindow(640, 480, "Euler vs Hamilton", NULL, NULL);
  if (!window)
  {
      glfwTerminate();
      exit(-1);
  }

  /* Make the window's context current */
  glfwMakeContextCurrent(window);
}

void initGlew()
{
  glewExperimental = GL_TRUE;
  glewInit();
}

void loadShaders()
{
  shader_program = glCreateProgram();

  GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertex_shader, 1, &vertex_glsl, NULL);
  glCompileShader(vertex_shader);
  shaderLog(vertex_shader);

  GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragment_shader, 1, &fragment_glsl, NULL);
  glCompileShader(fragment_shader);
  shaderLog(fragment_shader);

  glAttachShader(shader_program, vertex_shader);
  glAttachShader(shader_program, fragment_shader);

  glLinkProgram(shader_program);
  programLog(shader_program);

  glUseProgram(shader_program);

  view_location = glGetUniformLocation(shader_program, "view");
  projection_location = glGetUniformLocation(shader_program, "projection");
  world_location = glGetUniformLocation(shader_program, "world");
}

void loadGeometry()
{
  int i = 0;
  verts[i++] = -1.0f;
  verts[i++] = 0.0f;
  verts[i++] = -1.0f;

  verts[i++] = 1.0f;
  verts[i++] = 0.0f;
  verts[i++] = -1.0f;

  verts[i++] = 1.0f;
  verts[i++] = 0.0f;
  verts[i++] = 1.0f;

  verts[i++] = -1.0f;
  verts[i++] = 0.0f;
  verts[i++] = 1.0f;

  i = 0;
  faces[i++] = 0;
  faces[i++] = 2;
  faces[i++] = 1;

  faces[i++] = 0;
  faces[i++] = 3;
  faces[i++] = 2;

  GLuint vptr, iptr;

  glGenVertexArrays(1, &quad);
  glBindVertexArray(quad);

  glGenBuffers(1, &vptr);
  glBindBuffer(GL_ARRAY_BUFFER, vptr);

  glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(VERTEX_ARRAY_SIZE *
    sizeof(GLfloat)), verts, GL_STATIC_DRAW);

  glGenBuffers(1, &iptr);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iptr);

  glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(INDEX_ARRAY_SIZE *
    sizeof(GLuint)), faces, GL_STATIC_DRAW);

  glEnableVertexAttribArray(POSITION_LOC);
  glVertexAttribPointer(POSITION_LOC, VERTEX_SIZE, GL_FLOAT, GL_FALSE,
          (GLsizei)(VERTEX_SIZE * sizeof(GLfloat)), 0);

  world = scale(world, vec3(10,10,10));

  glUniformMatrix4fv(world_location, 1, GL_FALSE, value_ptr(world));
}

double getDifference(CamF* camf, CamD* camd)
{
  CamD::mat4_type matf = (CamD::mat4_type) camf->getMat();
  CamD::mat4_type matd = camd->getMat();

  double diff = 0;

  for (int i = 0; i < 4; i++)
  {
    tvec4<double,highp> v = column(matf, i) - column(matd, i);

    diff += (v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
  }

  return diff/16.0;
}

void handleArguments(int argc, char ** argv)
{
  for (int i = 1; i < argc; i++)
  {
    if (strcmp(argv[i], "-i") == 0)
    {
      i++;
      input_file.open(argv[i]);
      is_reading = true;
    }
    else if (strcmp(argv[i], "-o") == 0)
    {
      i++;
      output_file.open(argv[i]);
      is_writing = true;
    }
  }
}

int main(int argc, char ** argv)
{
  handleArguments(argc, argv);

  init();

  loadShaders();

  loadGeometry();

  cout << ("Euler, Quaternion") << endl;

  /* Loop until the user closes the window */
  while (!glfwWindowShouldClose(window))
  {
    mainLoop();
  }

  glfwTerminate();

  input_file.close();
  output_file.close();

  return 0;
}
<commit_msg>Only hide cursor if we're NOT on Apple<commit_after>#include "main.h"

void mainLoop()
{
  handleInput();

  glfwGetFramebufferSize(window, &width, &height);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // bottom-left: Euler Camera (float)
  drawQuarter(0, 0, width/2, height/2, rcamf);
  // bottom-right: Euler Camera (double)
  drawQuarter(width/2, 0, width/2, height/2, rcamd);

  // top-left: Quaternion Camera (float)
  drawQuarter(0, height/2, width/2, height/2, qcamf);
  // top-right: Quaternion Camera (double)
  drawQuarter(width/2, height/2, width/2, height/2, qcamd);

  double rdiff = getDifference(rcamf, rcamd);
  double qdiff = getDifference(qcamf, qcamd);

  cout.precision(15);
  cout << std::fixed << rdiff << ", " << qdiff << endl;

  /* Swap front and back buffers */
  glfwSwapBuffers(window);
  /* Poll for and process events */
  glfwPollEvents();
}

void handleInput()
{
  if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
  {
    glfwSetWindowShouldClose(window, GL_TRUE);
  }

  double x, y;
  int key;
  if (is_reading)
  {
    if (!(input_file >> mouse_ready))
    {
      glfwSetWindowShouldClose(window, GL_TRUE);
      return;
    }
    input_file >> x >> y;

    input_file >> key;
    while (key != -1)
    {
      doKeyToCameras(key);
      input_file >> key;
    }
  }
  else
  {
    glfwGetCursorPos(window, &x, &y);

    if (is_writing)
      output_file << mouse_ready << " " << x << " " << y << " ";

    for (unsigned i = 0; i < sizeof(KEYS)/sizeof(int); i++)
    {
      if (glfwGetKey(window, KEYS[i]) == GLFW_PRESS)
      {
        doKeyToCameras(KEYS[i]);

        if (is_writing)
          output_file << KEYS[i] << " ";
      }
    }

    if (is_writing)
      output_file << "-1" << endl;
  }
  mouseMoved(x, y);
}

void doKeyToCameras(int key)
{
  rcamf->doKey(key);
  rcamd->doKey(key);
  qcamf->doKey(key);
  qcamd->doKey(key);
}

void mouseCheck(GLFWwindow*,double x,double y)
{
  if (!mouse_ready)
  {
    mouse_ready = true;
    mx = x; my = y;

    if (is_writing)
      output_file << "0 " << mx << " " << my << " -1 ";
  }
}

void mouseMoved(double x, double y)
{
  if (mouse_ready)
  {
    double dx = x - mx;
    double dy = y - my;

    rcamf->mouseLook((float)dx,(float)dy);
    qcamf->mouseLook((float)dx,(float)dy);

    rcamd->mouseLook(dx,dy);
    qcamd->mouseLook(dx,dy);
  }

  mx = x; my = y;
}

void initGlfw()
{
  if (!glfwInit())
      exit(-1);

// Because Apple refuses to keep up with standards!
#ifdef __APPLE__
  glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
  glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
}

void init()
{
  initGlfw();
  initWindow();
  initGlew();

  if (!is_reading)
  {
// Because GLFW refuses to keep up with APPLE!
#ifndef __APPLE__
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
#endif
    glfwSetCursorPosCallback(window, mouseCheck);
  }

  glEnable(GL_VERTEX_ARRAY);
  glEnable(GL_DEPTH_TEST);
  glDisable(GL_CULL_FACE);

  glClearColor(1,1,1,1);
}

void initWindow()
{
  window = glfwCreateWindow(640, 480, "Euler vs Hamilton", NULL, NULL);
  if (!window)
  {
      glfwTerminate();
      exit(-1);
  }

  /* Make the window's context current */
  glfwMakeContextCurrent(window);
}

void initGlew()
{
  glewExperimental = GL_TRUE;
  glewInit();
}

void loadShaders()
{
  shader_program = glCreateProgram();

  GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertex_shader, 1, &vertex_glsl, NULL);
  glCompileShader(vertex_shader);
  shaderLog(vertex_shader);

  GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragment_shader, 1, &fragment_glsl, NULL);
  glCompileShader(fragment_shader);
  shaderLog(fragment_shader);

  glAttachShader(shader_program, vertex_shader);
  glAttachShader(shader_program, fragment_shader);

  glLinkProgram(shader_program);
  programLog(shader_program);

  glUseProgram(shader_program);

  view_location = glGetUniformLocation(shader_program, "view");
  projection_location = glGetUniformLocation(shader_program, "projection");
  world_location = glGetUniformLocation(shader_program, "world");
}

void loadGeometry()
{
  int i = 0;
  verts[i++] = -1.0f;
  verts[i++] = 0.0f;
  verts[i++] = -1.0f;

  verts[i++] = 1.0f;
  verts[i++] = 0.0f;
  verts[i++] = -1.0f;

  verts[i++] = 1.0f;
  verts[i++] = 0.0f;
  verts[i++] = 1.0f;

  verts[i++] = -1.0f;
  verts[i++] = 0.0f;
  verts[i++] = 1.0f;

  i = 0;
  faces[i++] = 0;
  faces[i++] = 2;
  faces[i++] = 1;

  faces[i++] = 0;
  faces[i++] = 3;
  faces[i++] = 2;

  GLuint vptr, iptr;

  glGenVertexArrays(1, &quad);
  glBindVertexArray(quad);

  glGenBuffers(1, &vptr);
  glBindBuffer(GL_ARRAY_BUFFER, vptr);

  glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(VERTEX_ARRAY_SIZE *
    sizeof(GLfloat)), verts, GL_STATIC_DRAW);

  glGenBuffers(1, &iptr);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iptr);

  glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(INDEX_ARRAY_SIZE *
    sizeof(GLuint)), faces, GL_STATIC_DRAW);

  glEnableVertexAttribArray(POSITION_LOC);
  glVertexAttribPointer(POSITION_LOC, VERTEX_SIZE, GL_FLOAT, GL_FALSE,
          (GLsizei)(VERTEX_SIZE * sizeof(GLfloat)), 0);

  world = scale(world, vec3(10,10,10));

  glUniformMatrix4fv(world_location, 1, GL_FALSE, value_ptr(world));
}

double getDifference(CamF* camf, CamD* camd)
{
  CamD::mat4_type matf = (CamD::mat4_type) camf->getMat();
  CamD::mat4_type matd = camd->getMat();

  double diff = 0;

  for (int i = 0; i < 4; i++)
  {
    tvec4<double,highp> v = column(matf, i) - column(matd, i);

    diff += (v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
  }

  return diff/16.0;
}

void handleArguments(int argc, char ** argv)
{
  for (int i = 1; i < argc; i++)
  {
    if (strcmp(argv[i], "-i") == 0)
    {
      i++;
      input_file.open(argv[i]);
      is_reading = true;
    }
    else if (strcmp(argv[i], "-o") == 0)
    {
      i++;
      output_file.open(argv[i]);
      is_writing = true;
    }
  }
}

int main(int argc, char ** argv)
{
  handleArguments(argc, argv);

  init();

  loadShaders();

  loadGeometry();

  cout << ("Euler, Quaternion") << endl;

  /* Loop until the user closes the window */
  while (!glfwWindowShouldClose(window))
  {
    mainLoop();
  }

  glfwTerminate();

  input_file.close();
  output_file.close();

  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdlib.h>

#include <vector>
#include <queue>

#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/chrono.hpp>

#include <boost/atomic.hpp>
#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>

#include <boost/thread/condition_variable.hpp>

#include "vtrc-server/vtrc-application.h"
#include "vtrc-server/vtrc-endpoint-iface.h"
#include "vtrc-server/vtrc-endpoint-tcp.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-thread-poll.h"
#include "vtrc-common/vtrc-sizepack-policy.h"

#include "vtrc-common/vtrc-hasher-iface.h"

#include "vtrc-common/vtrc-data-queue.h"
#include "vtrc-common/vtrc-conditional-queues.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"

namespace ba = boost::asio;

class main_app: public vtrc::server::application
{

public:

    main_app( )
    {}

private:

    void on_endpoint_started( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Start endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_stopped( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Stop endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_exception( vtrc::server::endpoint_iface *ep )
    {
        try {
            throw;
        } catch( const std::exception &ex ) {
            std::cout << "Endpoint exception '" << ep->string( )
                      << "': " << ex.what( ) << "\n";
        } catch( ... ) {
            throw;
        }
    }

    void on_new_connection_accepted(
                    vtrc::common::connection_iface* connection )
    {
        std::cout << "connection accepted\n";
    }

    void on_new_connection_ready(
                            vtrc::common::connection_iface* connection )
    {
        std::cout << "connection ready\n";
    }

    void on_connection_die( vtrc::common::connection_iface* connection )
    {
        std::cout << "connection die\n";
    }

    google::protobuf::Service *create_service(
            const std::string &name, vtrc::common::connection_iface* connection)
    {
        return NULL;
    }

};

int main( )
{

    typedef vtrc::common::conditional_queues<int, std::string>  cm_type_d;

    cm_type_d d;

    d.add_queue( 10 );
    d.write_queue( 10, "1234" );

    std::deque<std::string> data;

    cm_type_d::wait_result rr =
            d.read_queue( 10, data, boost::posix_time::microsec(1000));

    std::cout << rr << "\n";

    return 0;
    main_app app;
    vtrc::common::thread_poll poll(app.get_io_service( ), 4);

    boost::shared_ptr<vtrc::server::endpoint_iface> tcp_ep
            (vtrc::server::endpoints::tcp::create(app, "0.0.0.0", 44667));

    tcp_ep->start( );

    poll.join_all( );

    return 0;
}
<commit_msg>queues<commit_after>#include <iostream>
#include <stdlib.h>

#include <vector>
#include <queue>

#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/chrono.hpp>

#include <boost/atomic.hpp>
#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>

#include <boost/thread/condition_variable.hpp>

#include "vtrc-server/vtrc-application.h"
#include "vtrc-server/vtrc-endpoint-iface.h"
#include "vtrc-server/vtrc-endpoint-tcp.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-thread-poll.h"
#include "vtrc-common/vtrc-sizepack-policy.h"

#include "vtrc-common/vtrc-hasher-iface.h"

#include "vtrc-common/vtrc-data-queue.h"
#include "vtrc-common/vtrc-conditional-queues.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"

namespace ba = boost::asio;

class main_app: public vtrc::server::application
{

public:

    main_app( )
    {}

private:

    void on_endpoint_started( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Start endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_stopped( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Stop endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_exception( vtrc::server::endpoint_iface *ep )
    {
        try {
            throw;
        } catch( const std::exception &ex ) {
            std::cout << "Endpoint exception '" << ep->string( )
                      << "': " << ex.what( ) << "\n";
        } catch( ... ) {
            throw;
        }
    }

    void on_new_connection_accepted(
                    vtrc::common::connection_iface* connection )
    {
        std::cout << "connection accepted\n";
    }

    void on_new_connection_ready(
                            vtrc::common::connection_iface* connection )
    {
        std::cout << "connection ready\n";
    }

    void on_connection_die( vtrc::common::connection_iface* connection )
    {
        std::cout << "connection die\n";
    }

    google::protobuf::Service *create_service(
            const std::string &name, vtrc::common::connection_iface* connection)
    {
        return NULL;
    }

};

int main( )
{

    typedef vtrc::common::conditional_queues<int, std::string>  cm_type_d;

    cm_type_d d;

    d.add_queue( 10 );
    d.write_queue( 10, "1234" );

    std::deque<std::string> data;

    cm_type_d::wait_result rr =
            d.read_queue( 10, data, boost::chrono::microseconds(1000));

    std::cout << rr << "\n";

    return 0;
    main_app app;
    vtrc::common::thread_poll poll(app.get_io_service( ), 4);

    boost::shared_ptr<vtrc::server::endpoint_iface> tcp_ep
            (vtrc::server::endpoints::tcp::create(app, "0.0.0.0", 44667));

    tcp_ep->start( );

    poll.join_all( );

    return 0;
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkHierarchicalDataSetAlgorithm.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkHierarchicalDataSetAlgorithm.h"

#include "vtkCommand.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkDataSet.h"
#include "vtkHierarchicalDataSet.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"

vtkCxxRevisionMacro(vtkHierarchicalDataSetAlgorithm, "1.3");
vtkStandardNewMacro(vtkHierarchicalDataSetAlgorithm);

//----------------------------------------------------------------------------
// Instantiate object so that cell data is not passed to output.
vtkHierarchicalDataSetAlgorithm::vtkHierarchicalDataSetAlgorithm()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
}

//----------------------------------------------------------------------------
vtkHierarchicalDataSet* vtkHierarchicalDataSetAlgorithm::GetOutput()
{
  return this->GetOutput(0);
}

//----------------------------------------------------------------------------
vtkHierarchicalDataSet* vtkHierarchicalDataSetAlgorithm::GetOutput(int port)
{
  vtkDataObject* output =
    vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive())->
    GetCompositeOutputData(port);
  return vtkHierarchicalDataSet::SafeDownCast(output);
}

//----------------------------------------------------------------------------
void vtkHierarchicalDataSetAlgorithm::SetInput(vtkDataObject* input)
{
  this->SetInput(0, input);
}

//----------------------------------------------------------------------------
void vtkHierarchicalDataSetAlgorithm::SetInput(int index, vtkDataObject* input)
{
  if(input)
    {
    this->SetInputConnection(index, input->GetProducerPort());
    }
  else
    {
    // Setting a NULL input removes the connection.
    this->SetInputConnection(index, 0);
    }
}

//----------------------------------------------------------------------------
vtkDataObject* vtkHierarchicalDataSetAlgorithm::GetInput(int port)
{
  if (this->GetNumberOfInputConnections(port) < 1)
    {
    return 0;
    }
  return this->GetExecutive()->GetInputData(port, 0);
}

//----------------------------------------------------------------------------
int vtkHierarchicalDataSetAlgorithm::ProcessRequest(
  vtkInformation* request,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  // generate the data
  if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA()))
    {
    int retVal = this->RequestData(request, inputVector, outputVector);
    return retVal;
    }

  // execute information
  if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
    {
    if(request->Has(vtkStreamingDemandDrivenPipeline::FROM_OUTPUT_PORT()))
      {
      int outputPort = request->Get(
        vtkStreamingDemandDrivenPipeline::FROM_OUTPUT_PORT());
      vtkInformation* info = outputVector->GetInformationObject(outputPort);
      if (info)
        {
        info->Set(
          vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1);
        }
      }
    return this->RequestInformation(request, inputVector, outputVector);
    }

  // set update extent
 if(request->Has(
      vtkCompositeDataPipeline::REQUEST_UPDATE_EXTENT()))
    {
    return this->RequestUpdateExtent(request, inputVector, outputVector);
    }

 return this->Superclass::ProcessRequest(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int vtkHierarchicalDataSetAlgorithm::FillOutputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject");
  info->Set(vtkCompositeDataPipeline::COMPOSITE_DATA_TYPE_NAME(),
            "vtkHierarchicalDataSet");
  return 1;
}

//----------------------------------------------------------------------------
int vtkHierarchicalDataSetAlgorithm::FillInputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  // now add our info
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
  info->Set(vtkCompositeDataPipeline::INPUT_REQUIRED_COMPOSITE_DATA_TYPE(),
            "vtkHierarchicalDataSet");
  return 1;
}

//----------------------------------------------------------------------------
vtkExecutive* vtkHierarchicalDataSetAlgorithm::CreateDefaultExecutive()
{
  return vtkCompositeDataPipeline::New();
}

//----------------------------------------------------------------------------
void vtkHierarchicalDataSetAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<commit_msg>ENH: Added support for new pass<commit_after>/*=========================================================================

Program:   Visualization Toolkit
Module:    vtkHierarchicalDataSetAlgorithm.cxx

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkHierarchicalDataSetAlgorithm.h"

#include "vtkCommand.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkDataSet.h"
#include "vtkHierarchicalDataSet.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"

vtkCxxRevisionMacro(vtkHierarchicalDataSetAlgorithm, "1.4");
vtkStandardNewMacro(vtkHierarchicalDataSetAlgorithm);

//----------------------------------------------------------------------------
// Instantiate object so that cell data is not passed to output.
vtkHierarchicalDataSetAlgorithm::vtkHierarchicalDataSetAlgorithm()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
}

//----------------------------------------------------------------------------
vtkHierarchicalDataSet* vtkHierarchicalDataSetAlgorithm::GetOutput()
{
  return this->GetOutput(0);
}

//----------------------------------------------------------------------------
vtkHierarchicalDataSet* vtkHierarchicalDataSetAlgorithm::GetOutput(int port)
{
  vtkDataObject* output =
    vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive())->
    GetCompositeOutputData(port);
  return vtkHierarchicalDataSet::SafeDownCast(output);
}

//----------------------------------------------------------------------------
void vtkHierarchicalDataSetAlgorithm::SetInput(vtkDataObject* input)
{
  this->SetInput(0, input);
}

//----------------------------------------------------------------------------
void vtkHierarchicalDataSetAlgorithm::SetInput(int index, vtkDataObject* input)
{
  if(input)
    {
    this->SetInputConnection(index, input->GetProducerPort());
    }
  else
    {
    // Setting a NULL input removes the connection.
    this->SetInputConnection(index, 0);
    }
}

//----------------------------------------------------------------------------
vtkDataObject* vtkHierarchicalDataSetAlgorithm::GetInput(int port)
{
  if (this->GetNumberOfInputConnections(port) < 1)
    {
    return 0;
    }
  return this->GetExecutive()->GetInputData(port, 0);
}

//----------------------------------------------------------------------------
int vtkHierarchicalDataSetAlgorithm::ProcessRequest(
  vtkInformation* request,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  // generate the data
  if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA()))
    {
    int retVal = this->RequestData(request, inputVector, outputVector);
    return retVal;
    }

  // execute information
  if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
    {
    if(request->Has(vtkStreamingDemandDrivenPipeline::FROM_OUTPUT_PORT()))
      {
      int outputPort = request->Get(
        vtkStreamingDemandDrivenPipeline::FROM_OUTPUT_PORT());
      vtkInformation* info = outputVector->GetInformationObject(outputPort);
      if (info)
        {
        info->Set(
          vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1);
        }
      }
    return this->RequestInformation(request, inputVector, outputVector);
    }

  // set update extent
  if(request->Has(
       vtkCompositeDataPipeline::REQUEST_UPDATE_EXTENT()))
    {
    return this->RequestUpdateExtent(request, inputVector, outputVector);
    }

  if(request->Has(vtkCompositeDataPipeline::BEGIN_LOOP()))
    {
    return this->SetUpdateBlocks(request, inputVector, outputVector);
    }

  return this->Superclass::ProcessRequest(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int vtkHierarchicalDataSetAlgorithm::FillOutputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject");
  info->Set(vtkCompositeDataPipeline::COMPOSITE_DATA_TYPE_NAME(),
            "vtkHierarchicalDataSet");
  return 1;
}

//----------------------------------------------------------------------------
int vtkHierarchicalDataSetAlgorithm::FillInputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  // now add our info
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
  info->Set(vtkCompositeDataPipeline::INPUT_REQUIRED_COMPOSITE_DATA_TYPE(),
            "vtkHierarchicalDataSet");
  return 1;
}

//----------------------------------------------------------------------------
vtkExecutive* vtkHierarchicalDataSetAlgorithm::CreateDefaultExecutive()
{
  return vtkCompositeDataPipeline::New();
}

//----------------------------------------------------------------------------
void vtkHierarchicalDataSetAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<|endoftext|>