<commit_before>/*
    Copyright (C) 2016-2018 Chih-Hsuan Yen <yan12125@gmail.com>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "touchpaddevice.h"

#include <cmath>
#include <QDebug>
#include <QX11Info>
#include <libudev.h>
#include <LXQt/Settings>
#include <X11/Xatom.h>
#include <X11/extensions/XInput2.h>
#include <libinput-properties.h>

static QList<QVariant> xi2_get_device_property(int deviceid, const char* prop)
{
    QList<QVariant> ret;

    Display* dpy = QX11Info::display();

    Atom act_type;
    int act_format;
    unsigned long nitems, bytes_after;
    unsigned char *data, *ptr;
    Atom prop_atom = XInternAtom(dpy, prop, False);
    XIGetProperty(dpy, deviceid, prop_atom, 0, 1000, False, AnyPropertyType,
                  &act_type, &act_format, &nitems, &bytes_after, &data);
    ptr = data;
    for (unsigned long i = 0; i < nitems; i++)
    {
        switch (act_type)
        {
        case XA_INTEGER:
            switch (act_format)
            {
            case 8:
                ret << *reinterpret_cast<quint8*>(ptr);
                break;
            case 16:
                ret << *reinterpret_cast<quint16*>(ptr);
                break;
            case 32:
                ret << *reinterpret_cast<quint32*>(ptr);
                break;
            default:
                Q_ASSERT(0);
            }
            ptr += act_format / 8;
            break;
        case XA_STRING:
        {
            Q_ASSERT(act_format == 8);
            QString s(QString::fromUtf8(reinterpret_cast<char*>(ptr)));
            ptr += s.size() + 1; // including '\0'
            ret << s;
            break;
        }
        default:
            if (act_type == XInternAtom(dpy, "FLOAT", False)) {
                Q_ASSERT(act_format == 32);
                ret << *reinterpret_cast<float*>(ptr);
                ptr += 4;
            } else {
                qWarning() << "Unrecognized type" << act_type << "for property" << prop;
            }
        }
    }

    XFree(data);

    return ret;
}

static bool xi2_set_device_property(int deviceid, const char* prop, QList<QVariant> values)
{
    Display* dpy = QX11Info::display();

    Atom prop_atom = XInternAtom(dpy, prop, False);

    Atom act_type;
    int act_format;
    unsigned long nitems, bytes_after;
    unsigned char *data;
    float* float_data = nullptr;
    // get the property first to determine its type and format
    XIGetProperty(dpy, deviceid, prop_atom, 0, 1000, False, AnyPropertyType,
                  &act_type, &act_format, &nitems, &bytes_after, &data);
    if (!nitems)
    {
        return false;
    }

    XFree(data);

    auto dataType = values[0].type();
    switch (dataType)
    {
    case QVariant::Int:
        Q_ASSERT(act_type == XA_INTEGER);

        data = new unsigned char[values.size() * act_format / 8];
        for (int i = 0; i < values.size(); i++)
        {
            switch (act_format)
            {
            case 8:
                *reinterpret_cast<int8_t*>(data + i) = values[i].toInt();
                break;
            case 16:
                *reinterpret_cast<int16_t*>(data + i) = values[i].toInt();
                break;
            case 32:
                *reinterpret_cast<int32_t*>(data + i) = values[i].toInt();
                break;
            default:
                Q_ASSERT(0);
            }
        }
        break;
    case QMetaType::Float:
        Q_ASSERT(act_type == XInternAtom(dpy, "FLOAT", False));
        Q_ASSERT(act_format == 32);
        float_data = new float[values.size()];
        for (int i = 0; i < values.size(); i++)
        {
            float_data[i] = values[i].toFloat();
        }
        data = reinterpret_cast<unsigned char*>(float_data);
        break;
    default:
        qWarning() << "Unsupported data type" << dataType;
    }
    if (!data)
    {
        return false;
    }
    XIChangeProperty(dpy, deviceid, prop_atom, act_type, act_format,
                     XIPropModeReplace, data, values.size());
    // XXX How to catch errors?

    delete [] float_data;

    return true;
}

QList<QVariant> TouchpadDevice::get_xi2_property(const char* prop) const
{
    Q_ASSERT(deviceid);

    return xi2_get_device_property(deviceid, prop);
}

bool TouchpadDevice::set_xi2_property(const char* prop, QList<QVariant> values) const
{
    Q_ASSERT(deviceid);

    return xi2_set_device_property(deviceid, prop, values);
}

QList<TouchpadDevice> TouchpadDevice::enumerate_from_udev()
{
    QList<TouchpadDevice> ret;
    udev *ud = udev_new();

    if (!ud)
    {
        qWarning() << "Fails to initialize udev";
        return ret;
    }

    udev_enumerate *enumerate = udev_enumerate_new(ud);
    udev_enumerate_add_match_property(enumerate, "ID_INPUT_TOUCHPAD", "1");
    udev_enumerate_add_match_property(enumerate, "ID_INPUT_MOUSE", "1");
    udev_enumerate_scan_devices(enumerate);
    udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
    for (udev_list_entry *entry = devices; entry; entry = udev_list_entry_get_next(entry)) {
        const char *path = udev_list_entry_get_name(entry);
        udev_device *dev = udev_device_new_from_syspath(ud, path);

        const char* devnode = udev_device_get_devnode(dev);
        if (devnode)
        {
            TouchpadDevice dev;
            dev.devnode = QString::fromUtf8(devnode);
            if(dev.find_xi2_device())
            {
                qDebug() << "Detected" << dev.m_name << "on" << dev.devnode;
                dev.m_oldTappingEnabled = dev.tappingEnabled();
                dev.m_oldNaturalScrollingEnabled = dev.naturalScrollingEnabled();
                dev.m_oldTapToDragEnabled = dev.tapToDragEnabled();
                dev.m_oldAccelSpeed = dev.accelSpeed();
                dev.m_oldScrollingMethodEnabled = dev.scrollingMethodEnabled();
                ret << dev;
            }
        }

        udev_device_unref(dev);
    }
    udev_enumerate_unref(enumerate);
    udev_unref(ud);

    return ret;
}

bool TouchpadDevice::find_xi2_device()
{
    Display* dpy = QX11Info::display();

    int ndevices;
    bool found = false;
    XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &ndevices);

    for(int i = 0; i < ndevices ; i++)
    {
        QList<QVariant> devnode_prop = xi2_get_device_property(info[i].deviceid, "Device Node");
        if (devnode_prop.size() && devnode_prop[0].toString() == devnode)
        {
            m_name = QString::fromUtf8(info[i].name);
            deviceid = info[i].deviceid;
            found = true;
            break;
        }
    }

    XIFreeDeviceInfo(info);

    return found;
}

QString TouchpadDevice::escapedName() const
{
    // device names may contain '/' or '\\' so it should be escaped first
    // XXX: special characters are double escaped (see writeIniFile in qsettings.cpp)
    return QString::fromUtf8(QUrl::toPercentEncoding(name(), QByteArray(), QByteArray("/\\")));
}

void TouchpadDevice::loadSettings(LXQt::Settings* settings)
{
    QList<TouchpadDevice> devices = enumerate_from_udev();
    settings->beginGroup(QStringLiteral("Touchpad"));
    for (const TouchpadDevice& device : devices) {
        qDebug() << "Load settings for" << device.name();

        settings->beginGroup(device.escapedName());
        if (settings->contains(QLatin1String(TAPPING_ENABLED))) {
            device.setTappingEnabled(settings->value(QLatin1String(TAPPING_ENABLED)).toBool());
        }
        if (settings->contains(QLatin1String(NATURAL_SCROLLING_ENABLED))) {
            device.setNaturalScrollingEnabled(settings->value(QLatin1String(NATURAL_SCROLLING_ENABLED)).toBool());
        }
        if (settings->contains(QLatin1String(TAP_TO_DRAG_ENABLED))) {
            device.setTapToDragEnabled(settings->value(QLatin1String(TAP_TO_DRAG_ENABLED)).toBool());
        }
        if (settings->contains(QLatin1String(ACCELERATION_SPEED))) {
            device.setAccelSpeed(settings->value(QLatin1String(ACCELERATION_SPEED)).toFloat());
        }
        if (settings->contains(QLatin1String(SCROLLING_METHOD_ENABLED))) {
            device.setScrollingMethodEnabled(
                static_cast<ScrollingMethod>(settings->value(QLatin1String(SCROLLING_METHOD_ENABLED)).toInt()));
        }
        settings->endGroup();
    }
    settings->endGroup();
}

void TouchpadDevice::saveSettings(LXQt::Settings* settings) const
{
    settings->beginGroup(QStringLiteral("Touchpad"));

    settings->beginGroup(escapedName());
    settings->setValue(QLatin1String(TAPPING_ENABLED), tappingEnabled());
    settings->setValue(QLatin1String(NATURAL_SCROLLING_ENABLED), naturalScrollingEnabled());
    settings->setValue(QLatin1String(TAP_TO_DRAG_ENABLED), tapToDragEnabled());
    settings->setValue(QLatin1String(ACCELERATION_SPEED), accelSpeed());
    settings->setValue(QLatin1String(SCROLLING_METHOD_ENABLED), scrollingMethodEnabled());
    settings->endGroup(); // device name

    settings->endGroup(); // "Touchpad"
}

int TouchpadDevice::featureEnabled(const char* prop) const
{
    QList<QVariant> propVal = get_xi2_property(prop);
    if (propVal.size())
    {
        return propVal[0].toInt();
    }
    else
    {
        return -1;
    }
}

int TouchpadDevice::tappingEnabled() const
{
    return featureEnabled(LIBINPUT_PROP_TAP);
}

int TouchpadDevice::naturalScrollingEnabled() const
{
    return featureEnabled(LIBINPUT_PROP_NATURAL_SCROLL);
}

int TouchpadDevice::tapToDragEnabled() const
{
    return featureEnabled(LIBINPUT_PROP_TAP_DRAG);
}

float TouchpadDevice::accelSpeed() const
{
    QList<QVariant> propVal = get_xi2_property(LIBINPUT_PROP_ACCEL);
    if (propVal.size())
    {
        return propVal[0].toFloat();
    }
    else
    {
        return std::nanf("");
    }
}

bool TouchpadDevice::setTappingEnabled(bool enabled) const
{
    return set_xi2_property(LIBINPUT_PROP_TAP, QList<QVariant>({enabled ? 1 : 0}));
}

bool TouchpadDevice::setNaturalScrollingEnabled(bool enabled) const
{
    return set_xi2_property(LIBINPUT_PROP_NATURAL_SCROLL, QList<QVariant>({enabled ? 1 : 0}));
}

bool TouchpadDevice::setTapToDragEnabled(bool enabled) const
{
    return set_xi2_property(LIBINPUT_PROP_TAP_DRAG, QList<QVariant>({enabled ? 1 : 0}));
}

bool TouchpadDevice::setAccelSpeed(float speed) const
{
    return set_xi2_property(LIBINPUT_PROP_ACCEL, QList<QVariant>({speed}));
}

int TouchpadDevice::scrollMethodsAvailable() const
{
    QList<QVariant> values = get_xi2_property(LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE);

    if (!values.size()) {
        return 0;
    }

    Q_ASSERT(values.size() == 3);

    return (values[0].toInt() ? TWO_FINGER : 0) |
           (values[1].toInt() ? EDGE : 0) |
           (values[2].toInt() ? BUTTON : 0);
}

ScrollingMethod TouchpadDevice::scrollingMethodEnabled() const
{
    QList<QVariant> values = get_xi2_property(LIBINPUT_PROP_SCROLL_METHOD_ENABLED);

    if (!values.size()) {
        return NONE;
    }

    Q_ASSERT(values.size() == 3);

    // those methods are mutually exclusive
    if (values[0].toInt())
        return TWO_FINGER;
    else if (values[1].toInt())
        return EDGE;
    else if (values[2].toInt())
        return BUTTON;
    else
        return NONE;
}

bool TouchpadDevice::setScrollingMethodEnabled(ScrollingMethod method) const
{
    QList<QVariant> values;

    values << ((method == TWO_FINGER) ? 1 : 0);
    values << ((method == EDGE) ? 1 : 0);
    values << ((method == BUTTON) ? 1 : 0);

    return set_xi2_property(LIBINPUT_PROP_SCROLL_METHOD_ENABLED, values);
}
<commit_msg>Fix building with Qt 5.14<commit_after>/*
    Copyright (C) 2016-2018 Chih-Hsuan Yen <yan12125@gmail.com>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "touchpaddevice.h"

#include <cmath>
#include <QDebug>
#include <QX11Info>
#include <QUrl>
#include <libudev.h>
#include <LXQt/Settings>
#include <X11/Xatom.h>
#include <X11/extensions/XInput2.h>
#include <libinput-properties.h>

static QList<QVariant> xi2_get_device_property(int deviceid, const char* prop)
{
    QList<QVariant> ret;

    Display* dpy = QX11Info::display();

    Atom act_type;
    int act_format;
    unsigned long nitems, bytes_after;
    unsigned char *data, *ptr;
    Atom prop_atom = XInternAtom(dpy, prop, False);
    XIGetProperty(dpy, deviceid, prop_atom, 0, 1000, False, AnyPropertyType,
                  &act_type, &act_format, &nitems, &bytes_after, &data);
    ptr = data;
    for (unsigned long i = 0; i < nitems; i++)
    {
        switch (act_type)
        {
        case XA_INTEGER:
            switch (act_format)
            {
            case 8:
                ret << *reinterpret_cast<quint8*>(ptr);
                break;
            case 16:
                ret << *reinterpret_cast<quint16*>(ptr);
                break;
            case 32:
                ret << *reinterpret_cast<quint32*>(ptr);
                break;
            default:
                Q_ASSERT(0);
            }
            ptr += act_format / 8;
            break;
        case XA_STRING:
        {
            Q_ASSERT(act_format == 8);
            QString s(QString::fromUtf8(reinterpret_cast<char*>(ptr)));
            ptr += s.size() + 1; // including '\0'
            ret << s;
            break;
        }
        default:
            if (act_type == XInternAtom(dpy, "FLOAT", False)) {
                Q_ASSERT(act_format == 32);
                ret << *reinterpret_cast<float*>(ptr);
                ptr += 4;
            } else {
                qWarning() << "Unrecognized type" << act_type << "for property" << prop;
            }
        }
    }

    XFree(data);

    return ret;
}

static bool xi2_set_device_property(int deviceid, const char* prop, QList<QVariant> values)
{
    Display* dpy = QX11Info::display();

    Atom prop_atom = XInternAtom(dpy, prop, False);

    Atom act_type;
    int act_format;
    unsigned long nitems, bytes_after;
    unsigned char *data;
    float* float_data = nullptr;
    // get the property first to determine its type and format
    XIGetProperty(dpy, deviceid, prop_atom, 0, 1000, False, AnyPropertyType,
                  &act_type, &act_format, &nitems, &bytes_after, &data);
    if (!nitems)
    {
        return false;
    }

    XFree(data);

    auto dataType = values[0].type();
    switch (dataType)
    {
    case QVariant::Int:
        Q_ASSERT(act_type == XA_INTEGER);

        data = new unsigned char[values.size() * act_format / 8];
        for (int i = 0; i < values.size(); i++)
        {
            switch (act_format)
            {
            case 8:
                *reinterpret_cast<int8_t*>(data + i) = values[i].toInt();
                break;
            case 16:
                *reinterpret_cast<int16_t*>(data + i) = values[i].toInt();
                break;
            case 32:
                *reinterpret_cast<int32_t*>(data + i) = values[i].toInt();
                break;
            default:
                Q_ASSERT(0);
            }
        }
        break;
    case QMetaType::Float:
        Q_ASSERT(act_type == XInternAtom(dpy, "FLOAT", False));
        Q_ASSERT(act_format == 32);
        float_data = new float[values.size()];
        for (int i = 0; i < values.size(); i++)
        {
            float_data[i] = values[i].toFloat();
        }
        data = reinterpret_cast<unsigned char*>(float_data);
        break;
    default:
        qWarning() << "Unsupported data type" << dataType;
    }
    if (!data)
    {
        return false;
    }
    XIChangeProperty(dpy, deviceid, prop_atom, act_type, act_format,
                     XIPropModeReplace, data, values.size());
    // XXX How to catch errors?

    delete [] float_data;

    return true;
}

QList<QVariant> TouchpadDevice::get_xi2_property(const char* prop) const
{
    Q_ASSERT(deviceid);

    return xi2_get_device_property(deviceid, prop);
}

bool TouchpadDevice::set_xi2_property(const char* prop, QList<QVariant> values) const
{
    Q_ASSERT(deviceid);

    return xi2_set_device_property(deviceid, prop, values);
}

QList<TouchpadDevice> TouchpadDevice::enumerate_from_udev()
{
    QList<TouchpadDevice> ret;
    udev *ud = udev_new();

    if (!ud)
    {
        qWarning() << "Fails to initialize udev";
        return ret;
    }

    udev_enumerate *enumerate = udev_enumerate_new(ud);
    udev_enumerate_add_match_property(enumerate, "ID_INPUT_TOUCHPAD", "1");
    udev_enumerate_add_match_property(enumerate, "ID_INPUT_MOUSE", "1");
    udev_enumerate_scan_devices(enumerate);
    udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
    for (udev_list_entry *entry = devices; entry; entry = udev_list_entry_get_next(entry)) {
        const char *path = udev_list_entry_get_name(entry);
        udev_device *dev = udev_device_new_from_syspath(ud, path);

        const char* devnode = udev_device_get_devnode(dev);
        if (devnode)
        {
            TouchpadDevice dev;
            dev.devnode = QString::fromUtf8(devnode);
            if(dev.find_xi2_device())
            {
                qDebug() << "Detected" << dev.m_name << "on" << dev.devnode;
                dev.m_oldTappingEnabled = dev.tappingEnabled();
                dev.m_oldNaturalScrollingEnabled = dev.naturalScrollingEnabled();
                dev.m_oldTapToDragEnabled = dev.tapToDragEnabled();
                dev.m_oldAccelSpeed = dev.accelSpeed();
                dev.m_oldScrollingMethodEnabled = dev.scrollingMethodEnabled();
                ret << dev;
            }
        }

        udev_device_unref(dev);
    }
    udev_enumerate_unref(enumerate);
    udev_unref(ud);

    return ret;
}

bool TouchpadDevice::find_xi2_device()
{
    Display* dpy = QX11Info::display();

    int ndevices;
    bool found = false;
    XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &ndevices);

    for(int i = 0; i < ndevices ; i++)
    {
        QList<QVariant> devnode_prop = xi2_get_device_property(info[i].deviceid, "Device Node");
        if (devnode_prop.size() && devnode_prop[0].toString() == devnode)
        {
            m_name = QString::fromUtf8(info[i].name);
            deviceid = info[i].deviceid;
            found = true;
            break;
        }
    }

    XIFreeDeviceInfo(info);

    return found;
}

QString TouchpadDevice::escapedName() const
{
    // device names may contain '/' or '\\' so it should be escaped first
    // XXX: special characters are double escaped (see writeIniFile in qsettings.cpp)
    return QString::fromUtf8(QUrl::toPercentEncoding(name(), QByteArray(), QByteArray("/\\")));
}

void TouchpadDevice::loadSettings(LXQt::Settings* settings)
{
    QList<TouchpadDevice> devices = enumerate_from_udev();
    settings->beginGroup(QStringLiteral("Touchpad"));
    for (const TouchpadDevice& device : devices) {
        qDebug() << "Load settings for" << device.name();

        settings->beginGroup(device.escapedName());
        if (settings->contains(QLatin1String(TAPPING_ENABLED))) {
            device.setTappingEnabled(settings->value(QLatin1String(TAPPING_ENABLED)).toBool());
        }
        if (settings->contains(QLatin1String(NATURAL_SCROLLING_ENABLED))) {
            device.setNaturalScrollingEnabled(settings->value(QLatin1String(NATURAL_SCROLLING_ENABLED)).toBool());
        }
        if (settings->contains(QLatin1String(TAP_TO_DRAG_ENABLED))) {
            device.setTapToDragEnabled(settings->value(QLatin1String(TAP_TO_DRAG_ENABLED)).toBool());
        }
        if (settings->contains(QLatin1String(ACCELERATION_SPEED))) {
            device.setAccelSpeed(settings->value(QLatin1String(ACCELERATION_SPEED)).toFloat());
        }
        if (settings->contains(QLatin1String(SCROLLING_METHOD_ENABLED))) {
            device.setScrollingMethodEnabled(
                static_cast<ScrollingMethod>(settings->value(QLatin1String(SCROLLING_METHOD_ENABLED)).toInt()));
        }
        settings->endGroup();
    }
    settings->endGroup();
}

void TouchpadDevice::saveSettings(LXQt::Settings* settings) const
{
    settings->beginGroup(QStringLiteral("Touchpad"));

    settings->beginGroup(escapedName());
    settings->setValue(QLatin1String(TAPPING_ENABLED), tappingEnabled());
    settings->setValue(QLatin1String(NATURAL_SCROLLING_ENABLED), naturalScrollingEnabled());
    settings->setValue(QLatin1String(TAP_TO_DRAG_ENABLED), tapToDragEnabled());
    settings->setValue(QLatin1String(ACCELERATION_SPEED), accelSpeed());
    settings->setValue(QLatin1String(SCROLLING_METHOD_ENABLED), scrollingMethodEnabled());
    settings->endGroup(); // device name

    settings->endGroup(); // "Touchpad"
}

int TouchpadDevice::featureEnabled(const char* prop) const
{
    QList<QVariant> propVal = get_xi2_property(prop);
    if (propVal.size())
    {
        return propVal[0].toInt();
    }
    else
    {
        return -1;
    }
}

int TouchpadDevice::tappingEnabled() const
{
    return featureEnabled(LIBINPUT_PROP_TAP);
}

int TouchpadDevice::naturalScrollingEnabled() const
{
    return featureEnabled(LIBINPUT_PROP_NATURAL_SCROLL);
}

int TouchpadDevice::tapToDragEnabled() const
{
    return featureEnabled(LIBINPUT_PROP_TAP_DRAG);
}

float TouchpadDevice::accelSpeed() const
{
    QList<QVariant> propVal = get_xi2_property(LIBINPUT_PROP_ACCEL);
    if (propVal.size())
    {
        return propVal[0].toFloat();
    }
    else
    {
        return std::nanf("");
    }
}

bool TouchpadDevice::setTappingEnabled(bool enabled) const
{
    return set_xi2_property(LIBINPUT_PROP_TAP, QList<QVariant>({enabled ? 1 : 0}));
}

bool TouchpadDevice::setNaturalScrollingEnabled(bool enabled) const
{
    return set_xi2_property(LIBINPUT_PROP_NATURAL_SCROLL, QList<QVariant>({enabled ? 1 : 0}));
}

bool TouchpadDevice::setTapToDragEnabled(bool enabled) const
{
    return set_xi2_property(LIBINPUT_PROP_TAP_DRAG, QList<QVariant>({enabled ? 1 : 0}));
}

bool TouchpadDevice::setAccelSpeed(float speed) const
{
    return set_xi2_property(LIBINPUT_PROP_ACCEL, QList<QVariant>({speed}));
}

int TouchpadDevice::scrollMethodsAvailable() const
{
    QList<QVariant> values = get_xi2_property(LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE);

    if (!values.size()) {
        return 0;
    }

    Q_ASSERT(values.size() == 3);

    return (values[0].toInt() ? TWO_FINGER : 0) |
           (values[1].toInt() ? EDGE : 0) |
           (values[2].toInt() ? BUTTON : 0);
}

ScrollingMethod TouchpadDevice::scrollingMethodEnabled() const
{
    QList<QVariant> values = get_xi2_property(LIBINPUT_PROP_SCROLL_METHOD_ENABLED);

    if (!values.size()) {
        return NONE;
    }

    Q_ASSERT(values.size() == 3);

    // those methods are mutually exclusive
    if (values[0].toInt())
        return TWO_FINGER;
    else if (values[1].toInt())
        return EDGE;
    else if (values[2].toInt())
        return BUTTON;
    else
        return NONE;
}

bool TouchpadDevice::setScrollingMethodEnabled(ScrollingMethod method) const
{
    QList<QVariant> values;

    values << ((method == TWO_FINGER) ? 1 : 0);
    values << ((method == EDGE) ? 1 : 0);
    values << ((method == BUTTON) ? 1 : 0);

    return set_xi2_property(LIBINPUT_PROP_SCROLL_METHOD_ENABLED, values);
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#include "cql3/abstract_marker.hh"

#include "cql3/constants.hh"
#include "cql3/lists.hh"
#include "cql3/maps.hh"
#include "cql3/sets.hh"

namespace cql3 {

::shared_ptr<term> abstract_marker::raw::prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver)
{
    auto receiver_type = ::dynamic_pointer_cast<db::marshal::collection_type>(receiver->type);
    if (receiver_type != nullptr) {
        return ::make_shared<constants::marker>(_bind_index, receiver);
    }
    switch (receiver_type->kind) {
        case db::marshal::collection_type::collection_kind::LIST: return ::make_shared<lists::marker>(_bind_index, receiver);
        case db::marshal::collection_type::collection_kind::SET:  return ::make_shared<sets::marker>(_bind_index, receiver);
        case db::marshal::collection_type::collection_kind::MAP:  return ::make_shared<maps::marker>(_bind_index, receiver);
    }
    assert(0);
}

::shared_ptr<term> abstract_marker::in_raw::prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) {
    return ::make_shared<lists::marker>(_bind_index, make_in_receiver(receiver));
}

}
<commit_msg>cql3: Fix inverted condition in abstract_marker::raw::prepare()<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#include "cql3/abstract_marker.hh"

#include "cql3/constants.hh"
#include "cql3/lists.hh"
#include "cql3/maps.hh"
#include "cql3/sets.hh"

namespace cql3 {

::shared_ptr<term> abstract_marker::raw::prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver)
{
    auto receiver_type = ::dynamic_pointer_cast<db::marshal::collection_type>(receiver->type);
    if (receiver_type == nullptr) {
        return ::make_shared<constants::marker>(_bind_index, receiver);
    }
    switch (receiver_type->kind) {
        case db::marshal::collection_type::collection_kind::LIST: return ::make_shared<lists::marker>(_bind_index, receiver);
        case db::marshal::collection_type::collection_kind::SET:  return ::make_shared<sets::marker>(_bind_index, receiver);
        case db::marshal::collection_type::collection_kind::MAP:  return ::make_shared<maps::marker>(_bind_index, receiver);
    }
    assert(0);
}

::shared_ptr<term> abstract_marker::in_raw::prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) {
    return ::make_shared<lists::marker>(_bind_index, make_in_receiver(receiver));
}

}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    TestDelimitedTextReader.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 <vtkDelimitedTextReader.h>
#include <vtkTable.h>
#include <vtkTestUtilities.h>

// This test mainly tests the capability of the DelimitedTextReader accepting
//  both a file and a text string as the input
int TestDelimitedTextReader2(int argc, char *argv[])
{
  //------------  test the reader with an input file-----------------
  char* filename = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/authors.csv");

  vtkDelimitedTextReader *reader = vtkDelimitedTextReader::New();
  reader->SetFileName(filename);
  reader->SetHaveHeaders(1);
  reader->SetDetectNumericColumns(1);
  reader->Update();

  vtkTable* table = reader->GetOutput();
  table->Dump();
  cout << "Printing reader info..." << endl;
  reader->Print(cout);

  if (table->GetNumberOfRows() != 6)
    {
    cout << "ERROR: Wrong number of rows: " << table->GetNumberOfRows()<<endl;
    return 1;
    }
  if (table->GetNumberOfColumns() != 6)
    {
    cout << "ERROR: Wrong number of columns: " << table->GetNumberOfColumns()<<endl;
    return 1;
    }

  reader->Delete();

  //------------  test the reader with an input string-----------------
  char inputString[] = ",awesomeness,fitness,region\r\nAbby,1,2,china\r\nBob,5,0.2,US\r\nCatie,3,0.3,UK\r\nDavid,2,100,UK\r\nGrace,4,20,US\r\nIlknur,6,5,Turkey\r\n";

  vtkDelimitedTextReader *reader2 = vtkDelimitedTextReader::New();
  reader2->SetHaveHeaders(1);
  reader2->SetReadFromInputString(1);
  reader2->SetInputString(inputString);
  reader2->SetDetectNumericColumns(1);
  reader2->Update();

  vtkTable* table2 = reader2->GetOutput();
  table2->Dump();
  cout << "Printing reader2 info..." << endl;
  reader2->Print(cout);

  if (table2->GetNumberOfRows() != 6)
    {
    cout << "ERROR: Wrong number of rows: " << table2->GetNumberOfRows()<<endl;
    return 1;
    }
  if (table2->GetNumberOfColumns() != 4)
    {
    cout << "ERROR: Wrong number of columns: " << table2->GetNumberOfColumns()<<endl;
    return 1;
    }

  reader2->Delete();

  return 0;
}
<commit_msg>COMP: Memory leak<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestDelimitedTextReader.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 <vtkDelimitedTextReader.h>
#include <vtkTable.h>
#include <vtkTestUtilities.h>

// This test mainly tests the capability of the DelimitedTextReader accepting
//  both a file and a text string as the input
int TestDelimitedTextReader2(int argc, char *argv[])
{
  //------------  test the reader with an input file-----------------
  char* filename = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/authors.csv");

  vtkDelimitedTextReader *reader = vtkDelimitedTextReader::New();
  reader->SetFileName(filename);
  reader->SetHaveHeaders(1);
  reader->SetDetectNumericColumns(1);
  reader->Update();
  delete[] filename;

  vtkTable* table = reader->GetOutput();
  table->Dump();
  cout << "Printing reader info..." << endl;
  reader->Print(cout);

  if (table->GetNumberOfRows() != 6)
    {
    cout << "ERROR: Wrong number of rows: " << table->GetNumberOfRows()<<endl;
    return 1;
    }
  if (table->GetNumberOfColumns() != 6)
    {
    cout << "ERROR: Wrong number of columns: " << table->GetNumberOfColumns()<<endl;
    return 1;
    }

  reader->Delete();

  //------------  test the reader with an input string-----------------
  char inputString[] = ",awesomeness,fitness,region\r\nAbby,1,2,china\r\nBob,5,0.2,US\r\nCatie,3,0.3,UK\r\nDavid,2,100,UK\r\nGrace,4,20,US\r\nIlknur,6,5,Turkey\r\n";

  vtkDelimitedTextReader *reader2 = vtkDelimitedTextReader::New();
  reader2->SetHaveHeaders(1);
  reader2->SetReadFromInputString(1);
  reader2->SetInputString(inputString);
  reader2->SetDetectNumericColumns(1);
  reader2->Update();

  vtkTable* table2 = reader2->GetOutput();
  table2->Dump();
  cout << "Printing reader2 info..." << endl;
  reader2->Print(cout);

  if (table2->GetNumberOfRows() != 6)
    {
    cout << "ERROR: Wrong number of rows: " << table2->GetNumberOfRows()<<endl;
    return 1;
    }
  if (table2->GetNumberOfColumns() != 4)
    {
    cout << "ERROR: Wrong number of columns: " << table2->GetNumberOfColumns()<<endl;
    return 1;
    }

  reader2->Delete();

  return 0;
}
<|endoftext|>


<commit_before>#ifndef MDL_LATEX_DISPLAY_DRIVER_HPP
#define MDL_LATEX_DISPLAY_DRIVER_HPP

#include "display_driver.hpp"

/**
 * @brief LaTeX implementation of the DisplayDriver class
 **/
class LaTeXDisplayDriver : public DisplayDriver {
	public:
		LaTeXDisplayDriver() {};
		virtual ~LaTeXDisplayDriver() {};
		virtual void display(Document *doc);
		virtual void display(Document *doc, std::ostream & output);
};

#endif // MDL_LATEX_DISPLAY_DRIVER_HPP
<commit_msg>Handle DisplayDriver::_standalone in LaTeXDisplayDriver<commit_after>#ifndef MDL_LATEX_DISPLAY_DRIVER_HPP
#define MDL_LATEX_DISPLAY_DRIVER_HPP

#include "display_driver.hpp"

/**
 * @brief LaTeX implementation of the DisplayDriver class
 **/
class LaTeXDisplayDriver : public DisplayDriver {
	public:
		LaTeXDisplayDriver(bool standalone);
		virtual ~LaTeXDisplayDriver();
		virtual void display(Document *doc);
		virtual void display(Document *doc, std::ostream & output);
};

#endif // MDL_LATEX_DISPLAY_DRIVER_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include <fb/fbjni/CoreClasses.h>

#include <fb/assert.h>
#include <fb/log.h>

#include <alloca.h>
#include <cstdlib>
#include <ios>
#include <stdexcept>
#include <stdio.h>
#include <string>
#include <system_error>

#include <jni.h>

namespace facebook {
namespace jni {

namespace {
class JRuntimeException : public JavaClass<JRuntimeException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/RuntimeException;";

  static local_ref<JRuntimeException> create(const char* str) {
    return newInstance(make_jstring(str));
  }

  static local_ref<JRuntimeException> create() {
    return newInstance();
  }
};

class JIOException : public JavaClass<JIOException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/io/IOException;";

  static local_ref<JIOException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JOutOfMemoryError : public JavaClass<JOutOfMemoryError, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/OutOfMemoryError;";

  static local_ref<JOutOfMemoryError> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};
<commit_msg>Lines authored by ritzau<commit_after>/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include <fb/fbjni/CoreClasses.h>

#include <fb/assert.h>
#include <fb/log.h>

#include <alloca.h>
#include <cstdlib>
#include <ios>
#include <stdexcept>
#include <stdio.h>
#include <string>
#include <system_error>

#include <jni.h>

namespace facebook {
namespace jni {

namespace {
class JRuntimeException : public JavaClass<JRuntimeException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/RuntimeException;";

  static local_ref<JRuntimeException> create(const char* str) {
    return newInstance(make_jstring(str));
  }

  static local_ref<JRuntimeException> create() {
    return newInstance();
  }
};

class JIOException : public JavaClass<JIOException, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/io/IOException;";

  static local_ref<JIOException> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

class JOutOfMemoryError : public JavaClass<JOutOfMemoryError, JThrowable> {
 public:
  static auto constexpr kJavaDescriptor = "Ljava/lang/OutOfMemoryError;";

  static local_ref<JOutOfMemoryError> create(const char* str) {
    return newInstance(make_jstring(str));
  }
};

<|endoftext|>


<commit_before>#include <jni.h>
#include <v8.h>
#include <android/log.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <map>
#include "vatewrap.h"
#include "parmenides.h"

#include "pendercanvasjs/pendercanvasjs.h"

v8::Handle<v8::Value> ParmenidesHelperGetNothing(v8::Local<v8::String> property, const v8::AccessorInfo & info);
void ParmenidesHelperSetNothing(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo & info);
v8::Handle<v8::Value> ParmenidesConstructorHelper(const v8::Arguments & args);
std::string executeString( v8::Handle< v8::String > source, v8::Handle< v8::Value > name );

v8::Persistent<v8::Context> PrimaryContext;

v8::Handle<v8::FunctionTemplate> ParmenidesTemplate;

VateWrap * mPersistentVate;

std::string ObjectToString(v8::Local<v8::Value> value) {
  v8::String::Utf8Value utf8_value(value);
  return std::string(*utf8_value);
}

jstring Java_com_pender_PenderRenderer_test(JNIEnv*env,jobject obj) {

   v8::Persistent< v8::Context > context = v8::Context::New();
   return env->NewStringUTF( "Hello from JNI !");

}

extern "C" void Java_com_pender_cordovaplugin_PenderCordova_initvate(JNIEnv*env, jobject obj) {

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "INITIALIZING VATEWRAP");

    PenderCanvasJS penderCanvas;

//    Pender_Canvas_Function_Map.insert( pair<std::string,int>("foo",10));
/*
    const std::map<std::string,int> foo = penderCanvas.getFunctionMap();
    std::ostringstream stringStream;
    stringStream << foo["imgDraw"];
    std::string copyOfStr = stringStream.str();
    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", copyOfStr.c_str());
*/

    using namespace v8;

    // create the scope and context

    // governs local handles
    HandleScope localscope;
    // object template used to create the global object of our context
    Local< ObjectTemplate > global = ObjectTemplate::New();

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "Create Parmenides Function Template");

    // create a function template to wrap an object

    //embed an instance of the cpp class parmenides
    Parmenides nothing;
    // create an empty function template
    //Handle<FunctionTemplate> parmenidesTemplate = FunctionTemplate::New(ParmenidesConstructorHelper);
    ParmenidesTemplate = FunctionTemplate::New(ParmenidesConstructorHelper);

    // the instance template is an ObjectTemplate used to create objects when the function is used as a constructor

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "get the instance template");
    Handle<ObjectTemplate> nothingInstanceTemplate = ParmenidesTemplate->InstanceTemplate();
    // a single internal field will hold a reference to the corresponding c++ object
    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "got the instance template");
    nothingInstanceTemplate->SetInternalFieldCount(1);

    // add object properties
    nothingInstanceTemplate->SetAccessor(String::New("nothing"), ParmenidesHelperGetNothing, ParmenidesHelperSetNothing);
    //nothingInstanceTemplate->SetAccessor(String::New("something"), &Parmenides::getNothing, &Parmenides::setNothing);
    ParmenidesTemplate->SetCallHandler(ParmenidesConstructorHelper);

    // inject into global context
    char * cstr = new char[250];
    sprintf (cstr,"%d",ParmenidesTemplate);
    global->Set(String::New("Parmenides"), ParmenidesTemplate);

    // declaration and instantiation of the primary context
    PrimaryContext = v8::Context::New(NULL, global);

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "Initialized Template, inject into context");

   // v8::Context::Scope context_scope(PrimaryContext);

    penderCanvas.initCanvasFunctionTemplate();

    Handle<FunctionTemplate> canvasFunctionTemplate = penderCanvas._CanvasFunctionTemplate;

    Handle<ObjectTemplate> canvasInstanceTemplate = ParmenidesTemplate->InstanceTemplate();

    penderCanvas.injectInto(PrimaryContext);

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "Successfully Injected");

    // Test Parmenides
    Handle< String > name = String::New("The Edge of Sanity");
    Handle< String > cmd = String::New("function main() { var nothing = new Parmenides(); return nothing.nothing; } \n main();");

    std::string result = executeString(cmd, name);

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK: Executing Parmenides", result.c_str());

    delete [] cstr;

}

v8::Handle<v8::Value> ParmenidesHelperGetNothing(v8::Local<v8::String> property, const v8::AccessorInfo & info) {
	using namespace v8;
    return String::New("lunatic bastard");
}

void ParmenidesHelperSetNothing(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo & info) {

}

v8::Handle<v8::Value> ParmenidesConstructorHelper(const v8::Arguments & args) {
	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "PARMENIDES CONSTRUCTOR HELPER");
	using namespace v8;
	// throw if called without `new'
	if (!args.IsConstructCall()) {
		return ThrowException(String::New("Cannot call constructor as function, use with new"));
	}

	HandleScope scope;

	return v8::String::New("demicanadian battle-felon");

}

std::string executeString( v8::Handle< v8::String > source, v8::Handle< v8::Value > name ) {
	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "EXECUTING STRING");

    v8::HandleScope scope;
    v8::TryCatch tc;
    v8::Context::Scope context_scope(PrimaryContext);

    v8::Handle< v8::Script > script = v8::Script::Compile(source, name);

    if (script.IsEmpty()) {
        return std::string("Error: Script is empty!");
    }

    v8::Local< v8::Value > result = script->Run();

    if (result.IsEmpty()) {
    	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "RESULT IS EMPTY");
    	v8::String::Utf8Value error(tc.Exception());
    	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", std::string(*error).c_str());
    }
    v8::String::Utf8Value retstr(result);
    return std::string(*retstr);
}

/*
 *
 */
void initCanvasTemplate() {

}

/*

v8::Handle<v8::Value> NewParmenides (const v8::Arguments& args) {
	using namespace v8;
	HandleScope scope;
	Local<External> data = Local<External>::Cast(args.Data());
}

static inline v8::Handle<v8::Value> New( const v8::Arguments& args ) {
		v8::HandleScope scope;
		v8::Local<v8::External> edata = v8::Local<v8::External>::Cast(args.Data());
		ExposedClass* that = static_cast<ExposedClass*>(edata->Value());
		return that->createNew(args);
	}
*/
<commit_msg>bottle thrower test, working in thread other than main ui\!<commit_after>#include <jni.h>
#include <v8.h>
#include <android/log.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <map>
#include "vatewrap.h"
#include "parmenides.h"

#include "pendercanvasjs/pendercanvasjs.h"

v8::Handle<v8::Value> messageInABottle(const v8::Arguments & args);

v8::Persistent<v8::Context> PrimaryContext;

jstring Java_com_pender_PenderRenderer_test(JNIEnv*env,jobject obj) {

   v8::Persistent< v8::Context > context = v8::Context::New();
   return env->NewStringUTF( "Hello from JNI !");

}

extern "C" jstring Java_com_pender_PenderRenderer_bottleThrower(JNIEnv * env, jobject obj, jstring name, jstring message) {
    v8::HandleScope scope;
    v8::TryCatch tc;
    v8::Context::Scope context_scope(PrimaryContext);
    jstring retval;

    jboolean nameIsCopy;
    Handle< String > nme = String::New(env->GetStringChars(name,&nameIsCopy));
    Handle< String > cmd = String::New("function main() { var nothing = \"foobar\"; return nothing; } \n main();");

    v8::Handle< v8::Script > script = v8::Script::Compile(cmd, nme);

    __android_log_write(ANDROID_LOG_DEBUG, "VATEDROID Bottle Thrower", "Bottling Message");

    if (script.IsEmpty()) {
        return env->NewStringUTF("Error: Bottle is empty!");
    }

    __android_log_write(ANDROID_LOG_DEBUG, "VATEDROID Bottle Thrower", "Throwing Bottle");
    v8::Local< v8::Value > result = script->Run();

    if (result.IsEmpty()) {
        __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "RESULT IS EMPTY");
        v8::String::Utf8Value error(tc.Exception());
        __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", std::string(*error).c_str());
    }
    v8::String::Utf8Value retstr(result);
    retval = env->NewStringUTF(*retstr);
    return retval;
}

extern "C" void Java_com_pender_PenderRenderer_initvate(JNIEnv * env, jobject obj) {

    __android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "INITIALIZING VATEWRAP");

    using namespace v8;

    // create the scope and context

    // governs local handles
    HandleScope localscope;
    // object template used to create the global object of our context
    Local< ObjectTemplate > global = ObjectTemplate::New();
    // inject into global context
    global->Set(String::New("messageInABottle"), FunctionTemplate::New(messageInABottle));
    // declaration and instantiation of the primary context
    PrimaryContext = v8::Context::New(NULL, global);

}

v8::Handle<v8::Value> messageInABottle(const v8::Arguments & args) {
    return v8::String::New("demicanadian battle-felon");
}

/*
v8::Handle<v8::Value> ParmenidesHelperGetNothing(v8::Local<v8::String> property, const v8::AccessorInfo & info) {
	using namespace v8;
    return String::New("lunatic bastard");
}

void ParmenidesHelperSetNothing(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo & info) {

}

v8::Handle<v8::Value> ParmenidesConstructorHelper(const v8::Arguments & args) {
	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "PARMENIDES CONSTRUCTOR HELPER");
	using namespace v8;
	// throw if called without `new'
	if (!args.IsConstructCall()) {
		return ThrowException(String::New("Cannot call constructor as function, use with new"));
	}

	HandleScope scope;

	return v8::String::New("demicanadian battle-felon");

}

std::string executeString( v8::Handle< v8::String > source, v8::Handle< v8::Value > name ) {
	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "EXECUTING STRING");

    v8::HandleScope scope;
    v8::TryCatch tc;
    v8::Context::Scope context_scope(PrimaryContext);

    v8::Handle< v8::Script > script = v8::Script::Compile(source, name);

    if (script.IsEmpty()) {
        return std::string("Error: Script is empty!");
    }

    v8::Local< v8::Value > result = script->Run();

    if (result.IsEmpty()) {
    	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", "RESULT IS EMPTY");
    	v8::String::Utf8Value error(tc.Exception());
    	__android_log_write(ANDROID_LOG_DEBUG, "Pender NDK", std::string(*error).c_str());
    }
    v8::String::Utf8Value retstr(result);
    return std::string(*retstr);
}
*/

/*
 *
 */
void initCanvasTemplate() {

}

/*

v8::Handle<v8::Value> NewParmenides (const v8::Arguments& args) {
	using namespace v8;
	HandleScope scope;
	Local<External> data = Local<External>::Cast(args.Data());
}

static inline v8::Handle<v8::Value> New( const v8::Arguments& args ) {
		v8::HandleScope scope;
		v8::Local<v8::External> edata = v8::Local<v8::External>::Cast(args.Data());
		ExposedClass* that = static_cast<ExposedClass*>(edata->Value());
		return that->createNew(args);
	}
*/
<|endoftext|>


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

// A general interface for filtering and only acting on classes in Chromium C++
// code.

#include "ChromeClassTester.h"

using namespace clang;

namespace {

bool starts_with(const std::string& one, const std::string& two) {
  return one.substr(0, two.size()) == two;
}

bool ends_with(const std::string& one, const std::string& two) {
  if (two.size() > one.size())
    return false;

  return one.substr(one.size() - two.size(), two.size()) == two;
}

}  // namespace

ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
    : instance_(instance),
      diagnostic_(instance.getDiagnostics()) {
  banned_namespaces_.push_back("std");
  banned_namespaces_.push_back("__gnu_cxx");

  banned_directories_.push_back("third_party");
  banned_directories_.push_back("native_client");
  banned_directories_.push_back("breakpad");
  banned_directories_.push_back("courgette");
  banned_directories_.push_back("ppapi");
  banned_directories_.push_back("/usr");
  banned_directories_.push_back("testing");
  banned_directories_.push_back("googleurl");
  banned_directories_.push_back("v8");
  banned_directories_.push_back("sdch");

  // You are standing in a mazy of twisty dependencies, all resolved by
  // putting everything in the header.
  banned_directories_.push_back("chrome/test/automation");

  // Used in really low level threading code that probably shouldn't be out of
  // lined.
  ignored_record_names_.push_back("ThreadLocalBoolean");

  // A complicated pickle derived struct that is all packed integers.
  ignored_record_names_.push_back("Header");

  // Part of the GPU system that uses multiple included header
  // weirdness. Never getting this right.
  ignored_record_names_.push_back("Validators");

  // RAII class that's simple enough (media/base/callback.h).
  ignored_record_names_.push_back("AutoTaskRunner");
  ignored_record_names_.push_back("AutoCallbackRunner");

  // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
  ignored_record_names_.push_back("AutocompleteController");
  ignored_record_names_.push_back("HistoryURLProvider");

  // Because of chrome frame
  ignored_record_names_.push_back("ReliabilityTestSuite");

  // Part of our public interface that nacl and friends use. (Arguably, this
  // should mean that this is a higher priority but fixing this looks hard.)
  ignored_record_names_.push_back("PluginVersionInfo");
}

ChromeClassTester::~ChromeClassTester() {}

void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
  if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
    // If this is a POD or a class template or a type dependent on a
    // templated class, assume there's no ctor/dtor/virtual method
    // optimization that we can do.
    if (record->isPOD() ||
        record->getDescribedClassTemplate() ||
        record->getTemplateSpecializationKind() ||
        record->isDependentType())
      return;

    if (InBannedNamespace(record))
      return;

    SourceLocation record_location = record->getInnerLocStart();
    if (InBannedDirectory(record_location))
      return;

    // We sadly need to maintain a blacklist of types that violate these
    // rules, but do so for good reason or due to limitations of this
    // checker (i.e., we don't handle extern templates very well).
    std::string base_name = record->getNameAsString();
    if (IsIgnoredType(base_name))
      return;

    // We ignore all classes that end with "Matcher" because they're probably
    // GMock artifacts.
    if (ends_with(base_name, "Matcher"))
        return;

    CheckChromeClass(record_location, record);
  }
}

void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
  FullSourceLoc full(loc, instance().getSourceManager());
  std::string err;
  err = "[chromium-style] ";
  err += raw_error;
  unsigned id = diagnostic().getCustomDiagID(Diagnostic::Warning, err);
  DiagnosticBuilder B = diagnostic().Report(full, id);
}

bool ChromeClassTester::InTestingNamespace(Decl* record) {
  return GetNamespace(record).find("testing") != std::string::npos;
}

bool ChromeClassTester::InBannedNamespace(Decl* record) {
  std::string n = GetNamespace(record);
  if (n != "") {
    return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
        != banned_namespaces_.end();
  }

  return false;
}

std::string ChromeClassTester::GetNamespace(Decl* record) {
  return GetNamespaceImpl(record->getDeclContext(), "");
}

std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
                                                std::string candidate) {
  switch (context->getDeclKind()) {
    case Decl::TranslationUnit: {
      return candidate;
    }
    case Decl::Namespace: {
      const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
      std::string name_str;
      llvm::raw_string_ostream OS(name_str);
      if (decl->isAnonymousNamespace())
        OS << "<anonymous namespace>";
      else
        OS << decl;
      return GetNamespaceImpl(context->getParent(),
                              OS.str());
    }
    default: {
      return GetNamespaceImpl(context->getParent(), candidate);
    }
  }
}

bool ChromeClassTester::InBannedDirectory(const SourceLocation& loc) {
  if (loc.isFileID() && loc.isValid()) {
    bool invalid = false;
    const char* buffer_name = instance_.getSourceManager().getBufferName(
        loc, &invalid);
    if (!invalid && buffer_name) {
      std::string b(buffer_name);

      // Don't complain about these things in implementation files.
      if (ends_with(b, ".cc") || ends_with(b, ".cpp")) {
        return true;
      }

      // Don't complain about autogenerated protobuf files.
      if (ends_with(b, ".pb.h")) {
        return true;
      }

      // Strip out all preceding path garbage. Linux and mac builds have
      // different path garbage, but after doing this, the path should be
      // relative to the root of the source tree. (If we didn't require
      // relative paths, we could have just used realpath().)
      if (!b.empty() && b[0] != '/') {
        size_t i = 0;
        for (; i < b.size() && (b[i] == '.' || b[i] == '/'); ++i) {}
        b = b.substr(i);
      }

      for (std::vector<std::string>::const_iterator it =
               banned_directories_.begin();
           it != banned_directories_.end(); ++it) {
        if (starts_with(b, *it))
          return true;
      }
    }
  }

  return false;
}

bool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
  for (std::vector<std::string>::const_iterator it =
           ignored_record_names_.begin();
       it != ignored_record_names_.end(); ++it) {
    if (base_name == *it)
      return true;
  }

  return false;
}
<commit_msg>Add final ignores for Linux and note that mm files are implementation files.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// A general interface for filtering and only acting on classes in Chromium C++
// code.

#include "ChromeClassTester.h"

using namespace clang;

namespace {

bool starts_with(const std::string& one, const std::string& two) {
  return one.substr(0, two.size()) == two;
}

bool ends_with(const std::string& one, const std::string& two) {
  if (two.size() > one.size())
    return false;

  return one.substr(one.size() - two.size(), two.size()) == two;
}

}  // namespace

ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
    : instance_(instance),
      diagnostic_(instance.getDiagnostics()) {
  banned_namespaces_.push_back("std");
  banned_namespaces_.push_back("__gnu_cxx");

  banned_directories_.push_back("third_party");
  banned_directories_.push_back("native_client");
  banned_directories_.push_back("breakpad");
  banned_directories_.push_back("courgette");
  banned_directories_.push_back("ppapi");
  banned_directories_.push_back("/usr");
  banned_directories_.push_back("testing");
  banned_directories_.push_back("googleurl");
  banned_directories_.push_back("v8");
  banned_directories_.push_back("sdch");

  // You are standing in a mazy of twisty dependencies, all resolved by
  // putting everything in the header.
  banned_directories_.push_back("chrome/test/automation");

  // Used in really low level threading code that probably shouldn't be out of
  // lined.
  ignored_record_names_.push_back("ThreadLocalBoolean");

  // A complicated pickle derived struct that is all packed integers.
  ignored_record_names_.push_back("Header");

  // Part of the GPU system that uses multiple included header
  // weirdness. Never getting this right.
  ignored_record_names_.push_back("Validators");

  // RAII class that's simple enough (media/base/callback.h).
  ignored_record_names_.push_back("AutoTaskRunner");
  ignored_record_names_.push_back("AutoCallbackRunner");

  // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
  ignored_record_names_.push_back("AutocompleteController");
  ignored_record_names_.push_back("HistoryURLProvider");

  // Because of chrome frame
  ignored_record_names_.push_back("ReliabilityTestSuite");

  // Used over in the net unittests. A large enough bundle of integers with 1
  // non-pod class member. Probably harmless.
  ignored_record_names_.push_back("MockTransaction");

  // Used heavily in app_unittests and once in views_unittests. Fixing this
  // isn't worth the overhead of an additional library.
  ignored_record_names_.push_back("TestAnimationDelegate");

  // Part of our public interface that nacl and friends use. (Arguably, this
  // should mean that this is a higher priority but fixing this looks hard.)
  ignored_record_names_.push_back("PluginVersionInfo");
}

ChromeClassTester::~ChromeClassTester() {}

void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
  if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
    // If this is a POD or a class template or a type dependent on a
    // templated class, assume there's no ctor/dtor/virtual method
    // optimization that we can do.
    if (record->isPOD() ||
        record->getDescribedClassTemplate() ||
        record->getTemplateSpecializationKind() ||
        record->isDependentType())
      return;

    if (InBannedNamespace(record))
      return;

    SourceLocation record_location = record->getInnerLocStart();
    if (InBannedDirectory(record_location))
      return;

    // We sadly need to maintain a blacklist of types that violate these
    // rules, but do so for good reason or due to limitations of this
    // checker (i.e., we don't handle extern templates very well).
    std::string base_name = record->getNameAsString();
    if (IsIgnoredType(base_name))
      return;

    // We ignore all classes that end with "Matcher" because they're probably
    // GMock artifacts.
    if (ends_with(base_name, "Matcher"))
        return;

    CheckChromeClass(record_location, record);
  }
}

void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
  FullSourceLoc full(loc, instance().getSourceManager());
  std::string err;
  err = "[chromium-style] ";
  err += raw_error;
  unsigned id = diagnostic().getCustomDiagID(Diagnostic::Warning, err);
  DiagnosticBuilder B = diagnostic().Report(full, id);
}

bool ChromeClassTester::InTestingNamespace(Decl* record) {
  return GetNamespace(record).find("testing") != std::string::npos;
}

bool ChromeClassTester::InBannedNamespace(Decl* record) {
  std::string n = GetNamespace(record);
  if (n != "") {
    return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
        != banned_namespaces_.end();
  }

  return false;
}

std::string ChromeClassTester::GetNamespace(Decl* record) {
  return GetNamespaceImpl(record->getDeclContext(), "");
}

std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
                                                std::string candidate) {
  switch (context->getDeclKind()) {
    case Decl::TranslationUnit: {
      return candidate;
    }
    case Decl::Namespace: {
      const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
      std::string name_str;
      llvm::raw_string_ostream OS(name_str);
      if (decl->isAnonymousNamespace())
        OS << "<anonymous namespace>";
      else
        OS << decl;
      return GetNamespaceImpl(context->getParent(),
                              OS.str());
    }
    default: {
      return GetNamespaceImpl(context->getParent(), candidate);
    }
  }
}

bool ChromeClassTester::InBannedDirectory(const SourceLocation& loc) {
  if (loc.isFileID() && loc.isValid()) {
    bool invalid = false;
    const char* buffer_name = instance_.getSourceManager().getBufferName(
        loc, &invalid);
    if (!invalid && buffer_name) {
      std::string b(buffer_name);

      // Don't complain about these things in implementation files.
      if (ends_with(b, ".cc") || ends_with(b, ".cpp") || ends_with(b, ".mm")) {
        return true;
      }

      // Don't complain about autogenerated protobuf files.
      if (ends_with(b, ".pb.h")) {
        return true;
      }

      // Strip out all preceding path garbage. Linux and mac builds have
      // different path garbage, but after doing this, the path should be
      // relative to the root of the source tree. (If we didn't require
      // relative paths, we could have just used realpath().)
      if (!b.empty() && b[0] != '/') {
        size_t i = 0;
        for (; i < b.size() && (b[i] == '.' || b[i] == '/'); ++i) {}
        b = b.substr(i);
      }

      for (std::vector<std::string>::const_iterator it =
               banned_directories_.begin();
           it != banned_directories_.end(); ++it) {
        if (starts_with(b, *it))
          return true;
      }
    }
  }

  return false;
}

bool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
  for (std::vector<std::string>::const_iterator it =
           ignored_record_names_.begin();
       it != ignored_record_names_.end(); ++it) {
    if (base_name == *it)
      return true;
  }

  return false;
}
<|endoftext|>


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

#include "asylo/platform/system_call/system_call.h"

#include <fcntl.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <cerrno>
#include <cstring>
#include <string>
#include <vector>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/flags/flag.h"
#include "absl/strings/str_cat.h"
#include "asylo/platform/primitives/untrusted_primitives.h"
#include "asylo/platform/system_call/sysno.h"
#include "asylo/platform/system_call/type_conversions/types.h"
#include "asylo/platform/system_call/type_conversions/types_functions.h"
#include "asylo/platform/system_call/untrusted_invoke.h"
#include "asylo/test/util/test_flags.h"
#include "asylo/util/status_macros.h"

namespace asylo {
namespace system_call {
namespace {

using testing::Eq;
using testing::IsNull;
using testing::Not;
using testing::StrEq;

// A system call dispatch function which invokes a request message locally.
asylo::primitives::PrimitiveStatus SystemCallDispatcher(
    const uint8_t *request_buffer, size_t request_size,
    uint8_t **response_buffer, size_t *response_size) {
  primitives::Extent response;

  ASYLO_RETURN_IF_ERROR(
      UntrustedInvoke({request_buffer, request_size}, &response));

  *response_buffer = response.As<uint8_t>();
  *response_size = response.size();

  return asylo::primitives::PrimitiveStatus::OkStatus();
}

void error_handler(const char *message) {
  fprintf(stderr, "%s\n", message);
  fflush(stderr);
  abort();
}

// A system call dispatch function that return invalid response.
asylo::primitives::PrimitiveStatus InvalidResponseDispatcher(
    const uint8_t *request_buffer, size_t request_size,
    uint8_t **response_buffer, size_t *response_size) {
  primitives::Extent response;

  ASYLO_RETURN_IF_ERROR(
      UntrustedInvoke({request_buffer, request_size}, &response));

  *response_buffer = response.As<uint8_t>();
  *response_size = 1;

  return asylo::primitives::PrimitiveStatus::OkStatus();
}

// A system call dispatch function that always fails.
asylo::primitives::PrimitiveStatus AlwaysFailingDispatcher(
    const uint8_t *request_buffer, size_t request_size,
    uint8_t **response_buffer, size_t *response_size) {
  return {asylo::error::GoogleError::UNKNOWN, "some random failure"};
}

// Invokes a system call with zero parameters.
TEST(SystemCallTest, ZeroParameterTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  EXPECT_THAT(enc_untrusted_syscall(SYS_getpid), Eq(getpid()));
  EXPECT_THAT(enc_untrusted_syscall(SYS_geteuid), Eq(geteuid()));
  EXPECT_THAT(enc_untrusted_syscall(SYS_getgid), Eq(getgid()));
  EXPECT_THAT(enc_untrusted_syscall(SYS_getegid), Eq(getegid()));
}

// Invokes a system call which copies a buffer out of the kernel.
TEST(SystemCallTest, BufferOutTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  char buffer_expected[2048];
  char buffer_actual[2048];
  EXPECT_THAT(getcwd(buffer_expected, sizeof(buffer_expected)), Not(IsNull()));

  enc_untrusted_syscall(SYS_getcwd, buffer_actual, sizeof(buffer_actual));
  EXPECT_THAT(&buffer_expected[0], StrEq(buffer_actual));
}

// Invokes a system call which takes a scalar input parameter.
TEST(SystemCallTest, ScalarInTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  std::string path =
      absl::StrCat(absl::GetFlag(FLAGS_test_tmpdir), "/scalar_in_test.tmp");
  int fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

  EXPECT_GE(fd, 0);

  // Check fd is an open file descriptor.
  EXPECT_NE(fcntl(fd, F_GETFD), -1);

  EXPECT_THAT(enc_untrusted_syscall(SYS_close, fd), Eq(0));

  // Check fd is a closed file descriptor.
  EXPECT_THAT(fcntl(fd, F_GETFD), Eq(-1));
}

// Invokes a system call which takes a string input parameter.
TEST(SystemCallTest, StringInTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  std::string path =
      absl::StrCat(absl::GetFlag(FLAGS_test_tmpdir), "/string_in_test.tmp");
  int fd = enc_untrusted_syscall(SYS_open, path.c_str(),
                                 O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

  // Check a valid file descriptor was returned.
  EXPECT_GE(fd, 0);

  // Check fd is an open file descriptor.
  EXPECT_NE(fcntl(fd, F_GETFD), -1);

  // Check that the file exists and has the correct permissions.
  EXPECT_THAT(access(path.c_str(), R_OK | W_OK), Eq(0));

  close(fd);
}

// Invokes a system call and passes null values to in and out pointer
// parameters.
TEST(SystemCallTest, NullBufferTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  std::string path =
      absl::StrCat(absl::GetFlag(FLAGS_test_tmpdir), "/null_buffer_test.tmp");
  int fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

  // Check a valid file descriptor was returned.
  EXPECT_GE(fd, 0);

  // Write zero bytes to the file.
  EXPECT_THAT(enc_untrusted_syscall(SYS_write, fd, nullptr, 0), Eq(0));

  // Read zero bytes from the file.
  EXPECT_THAT(enc_untrusted_syscall(SYS_read, fd, nullptr, 0), Eq(0));
}

// Invokes a system call which copies a fixed size struct out of the kernel.
TEST(SystemCallTest, FixedOutTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);

  // Call stat on the temporary file directory.
  std::string path = absl::GetFlag(FLAGS_test_tmpdir);
  struct stat stat_expected;
  struct stat stat_actual;
  int result_expected = stat(path.c_str(), &stat_expected);
  int result_actual =
      enc_untrusted_syscall(SYS_stat, path.c_str(), &stat_actual);

  EXPECT_THAT(result_expected, Eq(result_actual));
  EXPECT_THAT(memcmp(&stat_expected, &stat_actual, sizeof(struct stat)), Eq(0));
}

// Invokes a system call which copies a fixed size array out of the kernel.
TEST(SystemCallTest, ArrayOutTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  int fd[2];
  EXPECT_THAT(enc_untrusted_syscall(SYS_pipe2, &fd, 0), Eq(0));
  const char message[] = "testing one, two, three...";
  int message_len = strlen(message) + 1;
  EXPECT_THAT(write(fd[1], &message, message_len), Eq(message_len));
  char buf[1024];
  EXPECT_THAT(read(fd[0], buf, sizeof(buf)), Eq(message_len));
  EXPECT_THAT(buf, StrEq(message));
  close(fd[0]);
  close(fd[1]);
}

// Ensure that a header file containing system call numbers was generated
// correctly.
TEST(SystemCallTest, SysCallNumbers) {
  EXPECT_EQ(kSYS_read, 0);
  EXPECT_EQ(kSYS_getcwd, 79);
}

TEST(SystemCallTest, AbortIfNoCallbackFunctionSet) {
  enc_set_dispatch_syscall(nullptr);
  EXPECT_THAT(enc_is_syscall_dispatcher_set(), Eq(false));
  EXPECT_EXIT(enc_untrusted_syscall(SYS_getpid),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that syscall aborts if callback function fails for any reason.
TEST(SystemCallTest, AbortOnCallbackFailure) {
  enc_set_dispatch_syscall(AlwaysFailingDispatcher);
  enc_set_error_handler(error_handler);
  EXPECT_EXIT(enc_untrusted_syscall(SYS_getpid),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that syscall aborts if incorrect sysno provided.
TEST(SystemCallTest, AbortOnSerializationFailure) {
  enc_set_error_handler(error_handler);
  EXPECT_EXIT(enc_untrusted_syscall(1000000),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that syscall aborts if incorrect response received.
TEST(SystemCallTest, AbortOnResponseMessageFailure) {
  enc_set_error_handler(error_handler);
  enc_set_dispatch_syscall(InvalidResponseDispatcher);
  EXPECT_EXIT(enc_untrusted_syscall(SYS_getpid),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that errno is correctly set if system call fails.
TEST(SystemCallTest, Errnotest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  int result = enc_untrusted_syscall(SYS_getcwd, nullptr, 1);
  EXPECT_THAT(result, Eq(-1));
  EXPECT_THAT(errno, Eq(ERANGE));
}

// Tests nanosleep return value and verifies conversions between klinux_timespec
// and timespec.
TEST(SystemCallTest, Nanosleeptest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);

  struct timespec req, rem;
  struct kLinux_timespec klinux_req, klinux_rem;
  req.tv_sec = 1;
  req.tv_nsec = 500000000L;  // 0.5 sec

  // Deliberately set incorrect values for output.
  klinux_rem.kLinux_tv_sec = 100;
  klinux_rem.kLinux_tv_nsec = 1000L;

  TokLinuxtimespec(&req, &klinux_req);

  // If klinux_req interprets order of members incorrectly from req, test will
  // suspend for 15 years!
  EXPECT_THAT(enc_untrusted_syscall(SYS_nanosleep, &klinux_req, &klinux_rem),
              Eq(0));

  FromkLinuxtimespec(&klinux_rem, &rem);
  EXPECT_THAT(klinux_rem.kLinux_tv_sec, Eq(0));
  EXPECT_THAT(klinux_rem.kLinux_tv_nsec, Eq(0));
}

TEST(SystemCallTest, BoundedBufferByParamLenTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);

  struct pollfd fds_actual[2], fds_expected[2];
  // Watch stdin for input.
  fds_actual[0].fd = STDIN_FILENO;
  fds_actual[0].events = POLLIN;
  fds_expected[0].fd = STDIN_FILENO;
  fds_expected[0].events = POLLIN;
  // Watch stdout for ability to write.
  fds_actual[1].fd = STDOUT_FILENO;
  fds_actual[1].events = POLLOUT;
  fds_expected[1].fd = STDOUT_FILENO;
  fds_expected[1].events = POLLOUT;

  EXPECT_THAT(poll(fds_expected, 2, 1000), Not(Eq(-1)));
  EXPECT_THAT(enc_untrusted_syscall(SYS_poll, fds_actual, 2, 10000),
              Not(Eq(-1)));
  EXPECT_THAT(fds_actual[0].revents, Eq(fds_expected[0].revents));
  EXPECT_THAT(fds_actual[1].revents, Eq(fds_actual[1].revents));
}

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

#include "asylo/platform/system_call/system_call.h"

#include <fcntl.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <cerrno>
#include <cstring>
#include <string>
#include <vector>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/flags/flag.h"
#include "absl/strings/str_cat.h"
#include "asylo/platform/primitives/untrusted_primitives.h"
#include "asylo/platform/system_call/sysno.h"
#include "asylo/platform/system_call/type_conversions/types.h"
#include "asylo/platform/system_call/type_conversions/types_functions.h"
#include "asylo/platform/system_call/untrusted_invoke.h"
#include "asylo/test/util/test_flags.h"
#include "asylo/util/status_macros.h"

namespace asylo {
namespace system_call {
namespace {

using testing::Eq;
using testing::IsNull;
using testing::Not;
using testing::StrEq;

// A system call dispatch function which invokes a request message locally.
asylo::primitives::PrimitiveStatus SystemCallDispatcher(
    const uint8_t *request_buffer, size_t request_size,
    uint8_t **response_buffer, size_t *response_size) {
  primitives::Extent response;

  ASYLO_RETURN_IF_ERROR(
      UntrustedInvoke({request_buffer, request_size}, &response));

  *response_buffer = response.As<uint8_t>();
  *response_size = response.size();

  return asylo::primitives::PrimitiveStatus::OkStatus();
}

void error_handler(const char *message) {
  fprintf(stderr, "%s\n", message);
  fflush(stderr);
  abort();
}

// A system call dispatch function that return invalid response.
asylo::primitives::PrimitiveStatus InvalidResponseDispatcher(
    const uint8_t *request_buffer, size_t request_size,
    uint8_t **response_buffer, size_t *response_size) {
  primitives::Extent response;

  ASYLO_RETURN_IF_ERROR(
      UntrustedInvoke({request_buffer, request_size}, &response));

  *response_buffer = response.As<uint8_t>();
  *response_size = 1;

  return asylo::primitives::PrimitiveStatus::OkStatus();
}

// A system call dispatch function that always fails.
asylo::primitives::PrimitiveStatus AlwaysFailingDispatcher(
    const uint8_t *request_buffer, size_t request_size,
    uint8_t **response_buffer, size_t *response_size) {
  return {asylo::error::GoogleError::UNKNOWN, "some random failure"};
}

// Invokes a system call with zero parameters.
TEST(SystemCallTest, ZeroParameterTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  EXPECT_THAT(enc_untrusted_syscall(SYS_getpid), Eq(getpid()));
  EXPECT_THAT(enc_untrusted_syscall(SYS_geteuid), Eq(geteuid()));
  EXPECT_THAT(enc_untrusted_syscall(SYS_getgid), Eq(getgid()));
  EXPECT_THAT(enc_untrusted_syscall(SYS_getegid), Eq(getegid()));
}

// Invokes a system call which copies a buffer out of the kernel.
TEST(SystemCallTest, BufferOutTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  char buffer_expected[2048];
  char buffer_actual[2048];
  EXPECT_THAT(getcwd(buffer_expected, sizeof(buffer_expected)), Not(IsNull()));

  enc_untrusted_syscall(SYS_getcwd, buffer_actual, sizeof(buffer_actual));
  EXPECT_THAT(&buffer_expected[0], StrEq(buffer_actual));
}

// Invokes a system call which takes a scalar input parameter.
TEST(SystemCallTest, ScalarInTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  std::string path =
      absl::StrCat(absl::GetFlag(FLAGS_test_tmpdir), "/scalar_in_test.tmp");
  int fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

  EXPECT_GE(fd, 0);

  // Check fd is an open file descriptor.
  EXPECT_NE(fcntl(fd, F_GETFD), -1);

  EXPECT_THAT(enc_untrusted_syscall(SYS_close, fd), Eq(0));

  // Check fd is a closed file descriptor.
  EXPECT_THAT(fcntl(fd, F_GETFD), Eq(-1));
}

// Invokes a system call which takes a string input parameter.
TEST(SystemCallTest, StringInTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  std::string path =
      absl::StrCat(absl::GetFlag(FLAGS_test_tmpdir), "/string_in_test.tmp");
  int fd = enc_untrusted_syscall(SYS_open, path.c_str(),
                                 O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

  // Check a valid file descriptor was returned.
  EXPECT_GE(fd, 0);

  // Check fd is an open file descriptor.
  EXPECT_NE(fcntl(fd, F_GETFD), -1);

  // Check that the file exists and has the correct permissions.
  EXPECT_THAT(access(path.c_str(), R_OK | W_OK), Eq(0));

  close(fd);
}

// Invokes a system call and passes null values to in and out pointer
// parameters.
TEST(SystemCallTest, NullBufferTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  std::string path =
      absl::StrCat(absl::GetFlag(FLAGS_test_tmpdir), "/null_buffer_test.tmp");
  int fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

  // Check a valid file descriptor was returned.
  EXPECT_GE(fd, 0);

  // Write zero bytes to the file.
  EXPECT_THAT(enc_untrusted_syscall(SYS_write, fd, nullptr, 0), Eq(0));

  // Read zero bytes from the file.
  EXPECT_THAT(enc_untrusted_syscall(SYS_read, fd, nullptr, 0), Eq(0));
}

// Invokes a system call which copies a fixed size struct out of the kernel.
TEST(SystemCallTest, FixedOutTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);

  // Call stat on the temporary file directory.
  std::string path = absl::GetFlag(FLAGS_test_tmpdir);
  struct stat stat_expected;
  struct stat stat_actual;
  int result_expected = stat(path.c_str(), &stat_expected);
  int result_actual =
      enc_untrusted_syscall(SYS_stat, path.c_str(), &stat_actual);

  EXPECT_THAT(result_expected, Eq(result_actual));
  EXPECT_THAT(memcmp(&stat_expected, &stat_actual, sizeof(struct stat)), Eq(0));
}

// Invokes a system call which copies a fixed size array out of the kernel.
TEST(SystemCallTest, ArrayOutTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  int fd[2];
  EXPECT_THAT(enc_untrusted_syscall(SYS_pipe2, &fd, 0), Eq(0));
  const char message[] = "testing one, two, three...";
  int message_len = strlen(message) + 1;
  EXPECT_THAT(write(fd[1], &message, message_len), Eq(message_len));
  char buf[1024];
  EXPECT_THAT(read(fd[0], buf, sizeof(buf)), Eq(message_len));
  EXPECT_THAT(buf, StrEq(message));
  close(fd[0]);
  close(fd[1]);
}

// Ensure that a header file containing system call numbers was generated
// correctly.
TEST(SystemCallTest, SysCallNumbers) {
  EXPECT_EQ(kSYS_read, 0);
  EXPECT_EQ(kSYS_getcwd, 79);
}

TEST(SystemCallTest, AbortIfNoCallbackFunctionSet) {
  enc_set_dispatch_syscall(nullptr);
  EXPECT_THAT(enc_is_syscall_dispatcher_set(), Eq(false));
  EXPECT_EXIT(enc_untrusted_syscall(SYS_getpid),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that syscall aborts if callback function fails for any reason.
TEST(SystemCallTest, AbortOnCallbackFailure) {
  enc_set_dispatch_syscall(AlwaysFailingDispatcher);
  enc_set_error_handler(error_handler);
  EXPECT_EXIT(enc_untrusted_syscall(SYS_getpid),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that syscall aborts if incorrect sysno provided.
TEST(SystemCallTest, AbortOnSerializationFailure) {
  enc_set_error_handler(error_handler);
  EXPECT_EXIT(enc_untrusted_syscall(1000000),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that syscall aborts if incorrect response received.
TEST(SystemCallTest, AbortOnResponseMessageFailure) {
  enc_set_error_handler(error_handler);
  enc_set_dispatch_syscall(InvalidResponseDispatcher);
  EXPECT_EXIT(enc_untrusted_syscall(SYS_getpid),
              ::testing::KilledBySignal(SIGABRT), ".*");
}

// Ensure that errno is correctly set if system call fails.
TEST(SystemCallTest, Errnotest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);
  int result = enc_untrusted_syscall(SYS_getcwd, nullptr, 1);
  EXPECT_THAT(result, Eq(-1));
  EXPECT_THAT(errno, Eq(ERANGE));
}

// Tests nanosleep return value and verifies conversions between klinux_timespec
// and timespec.
TEST(SystemCallTest, Nanosleeptest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);

  struct timespec req, rem;
  struct kLinux_timespec klinux_req, klinux_rem;
  req.tv_sec = 1;
  req.tv_nsec = 500000000L;  // 0.5 sec

  // Deliberately set incorrect values for output.
  klinux_rem.kLinux_tv_sec = 100;
  klinux_rem.kLinux_tv_nsec = 1000L;

  TokLinuxtimespec(&req, &klinux_req);

  // If klinux_req interprets order of members incorrectly from req, test will
  // suspend for 15 years!
  EXPECT_THAT(enc_untrusted_syscall(SYS_nanosleep, &klinux_req, &klinux_rem),
              Eq(0));

  FromkLinuxtimespec(&klinux_rem, &rem);
  EXPECT_THAT(klinux_rem.kLinux_tv_sec, Eq(0));
  EXPECT_THAT(klinux_rem.kLinux_tv_nsec, Eq(0));
}

TEST(SystemCallTest, BoundedBufferByParamLenTest) {
  enc_set_dispatch_syscall(SystemCallDispatcher);

  struct pollfd fds_actual[2], fds_expected[2];
  // Watch stdin for input.
  fds_actual[0].fd = STDIN_FILENO;
  fds_actual[0].events = POLLIN;
  fds_actual[0].revents = -1;
  fds_expected[0].fd = STDIN_FILENO;
  fds_expected[0].events = POLLIN;
  // Watch stdout for ability to write.
  fds_actual[1].fd = STDOUT_FILENO;
  fds_actual[1].events = POLLOUT;
  fds_actual[1].revents = -1;
  fds_expected[1].fd = STDOUT_FILENO;
  fds_expected[1].events = POLLOUT;

  EXPECT_THAT(poll(fds_expected, 2, 1000), Not(Eq(-1)));
  EXPECT_THAT(enc_untrusted_syscall(SYS_poll, fds_actual, 2, 10000),
              Not(Eq(-1)));
  EXPECT_THAT(fds_actual[0].revents, Eq(fds_expected[0].revents));
  EXPECT_THAT(fds_actual[1].revents, Eq(fds_actual[1].revents));
}

}  // namespace
}  // namespace system_call
}  // namespace asylo
<|endoftext|>