<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2013 Steven Lovegrove
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <pangolin/video_splitter.h>

namespace pangolin
{

VideoSplitter::VideoSplitter(VideoInterface *videoin, const std::vector<StreamInfo>& streams)
    : videoin(videoin), streams(streams)
{
    if(videoin->Streams().size() != 1)
        throw VideoException("VideoSplitter input must have exactly one stream");
}

VideoSplitter::~VideoSplitter()
{
    delete videoin;
}

size_t VideoSplitter::SizeBytes() const
{
    return videoin->SizeBytes();
}

const std::vector<StreamInfo>& VideoSplitter::Streams() const
{
    return streams;
}

void VideoSplitter::Start()
{
    videoin->Start();
}

void VideoSplitter::Stop()
{
    videoin->Stop();
}

bool VideoSplitter::GrabNext( unsigned char* image, bool wait )
{
    return videoin->GrabNext(image, wait);
}

bool VideoSplitter::GrabNewest( unsigned char* image, bool wait )
{
    return videoin->GrabNewest(image, wait);
}

}
<commit_msg>Add memory bounds checks for stream splits.<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2013 Steven Lovegrove
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <pangolin/video_splitter.h>

namespace pangolin
{

VideoSplitter::VideoSplitter(VideoInterface *videoin, const std::vector<StreamInfo>& streams)
    : videoin(videoin), streams(streams)
{
    if(videoin->Streams().size() != 1)
        throw VideoException("VideoSplitter input must have exactly one stream");

    // Make sure no stream over-runs input stream
    for(unsigned int i=0; i < streams.size(); ++i) {
        if(videoin->Streams()[0].SizeBytes() < (size_t)streams[i].Offset() + streams[i].SizeBytes() )
            throw VideoException("VideoSplitter: stream extends past end of input");
    }
}

VideoSplitter::~VideoSplitter()
{
    delete videoin;
}

size_t VideoSplitter::SizeBytes() const
{
    return videoin->SizeBytes();
}

const std::vector<StreamInfo>& VideoSplitter::Streams() const
{
    return streams;
}

void VideoSplitter::Start()
{
    videoin->Start();
}

void VideoSplitter::Stop()
{
    videoin->Stop();
}

bool VideoSplitter::GrabNext( unsigned char* image, bool wait )
{
    return videoin->GrabNext(image, wait);
}

bool VideoSplitter::GrabNewest( unsigned char* image, bool wait )
{
    return videoin->GrabNewest(image, wait);
}

}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2011-2012 - Tőkés Attila
  Copyright (C) 2015 Daniel Nicoletti <dantti12@gmail.com>

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

  This library 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
  Lesser General Public License for more details.

  See the LICENSE file for more details.
*/

#include "mimemessage_p.h"

#include <QtCore/QDebug>
#include "quotedprintable.h"
#include <typeinfo>

#include <QDateTime>
#include <QLoggingCategory>

Q_LOGGING_CATEGORY(SIMPLEMAIL_MIMEMSG, "simplemail.mimemessage")

using namespace SimpleMail;

MimeMessage::MimeMessage(bool createAutoMimeContent) : d(new MimeMessagePrivate)
{
    if (createAutoMimeContent) {
        d->content = new MimeMultiPart();
    }

    d->autoMimeContentCreated = createAutoMimeContent;
}

MimeMessage::MimeMessage(const MimeMessage &other) : d(other.d)
{

}

MimeMessage::~MimeMessage()
{

}

MimeMessage &MimeMessage::operator=(const MimeMessage &other)
{
    d = other.d;
    return *this;
}

MimePart& MimeMessage::getContent()
{
    return *d->content;
}

void MimeMessage::setContent(MimePart *content)
{
    if (d->autoMimeContentCreated) {
      d->autoMimeContentCreated = false;
      delete d->content;
    }
    d->content = content;
}

bool MimeMessage::write(QIODevice *device) const
{
    // Headers
    QByteArray data;

    if (!d->listExtraHeaders.isEmpty()) {
        const auto listExtraHeaders = d->listExtraHeaders;
        for (const QByteArray &header : listExtraHeaders) {
            data += MimeMessagePrivate::encodeData(d->encoding, QString::fromLatin1(header), true) + QByteArrayLiteral("\r\n");
        }
        if (device->write(data) != data.size()) {
            return false;
        }
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("From: "), QList<EmailAddress>() << d->sender, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    if (d->replyTo.address().isEmpty() == false) {
        data = MimeMessagePrivate::encode(QByteArrayLiteral("Reply-To: "), QList<EmailAddress>() << d->replyTo, d->encoding);
        if (device->write(data) != data.size()) {
            return false;
        }
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("To: "), d->recipientsTo, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("Cc: "), d->recipientsCc, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("Date: ") + QDateTime::currentDateTime().toString(Qt::RFC2822Date).toLatin1() + QByteArrayLiteral("\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("Subject: ") + MimeMessagePrivate::encodeData(d->encoding, d->subject, true);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("\r\nMIME-Version: 1.0\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    if (!d->content->write(device)) {
        return false;
    }

    // Send \r\n.\r\n to end the mail data
    device->write(QByteArrayLiteral("\r\n.\r\n"));

    return true;
}

void MimeMessage::setSender(const EmailAddress &sender)
{
    d->sender = sender;
}

void MimeMessage::setToRecipients(const QList<EmailAddress> &toList)
{
    d->recipientsTo = toList;
}

QList<EmailAddress> MimeMessage::toRecipients() const
{
    return d->recipientsTo;
}

void MimeMessage::addTo(const EmailAddress &rcpt)
{
    d->recipientsTo.append(rcpt);
}

void MimeMessage::setCcRecipients(const QList<EmailAddress> &ccList)
{
    d->recipientsCc = ccList;
}

void MimeMessage::addCc(const EmailAddress &rcpt)
{
    d->recipientsCc.append(rcpt);
}

QList<EmailAddress> MimeMessage::ccRecipients() const
{
    return d->recipientsCc;
}

void MimeMessage::setBccRecipients(const QList<EmailAddress> &bccList)
{
    d->recipientsBcc = bccList;
}

QList<EmailAddress> MimeMessage::bccRecipients() const
{
    return d->recipientsBcc;
}

void MimeMessage::addBcc(const EmailAddress &rcpt)
{
    d->recipientsBcc.append(rcpt);
}

void MimeMessage::setSubject(const QString &subject)
{
    d->subject = subject;
}

void MimeMessage::addPart(MimePart *part)
{
    auto content = d->content;
    if (typeid(*content) == typeid(MimeMultiPart)) {
        static_cast<MimeMultiPart*>(d->content)->addPart(part);
    }
}

void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{
    d->encoding = hEnc;
}

void MimeMessage::addHeader(const QByteArray &headerName, const QByteArray &headerValue)
{
    d->listExtraHeaders.append(headerName + ":" + headerValue);
}

QList<QByteArray> MimeMessage::getHeaders() const
{
    return d->listExtraHeaders;
}

EmailAddress MimeMessage::sender() const
{
    return d->sender;
}

void MimeMessage::setReplyto(const EmailAddress &replyTo)
{
    d->replyTo = replyTo;
}

QString MimeMessage::subject() const
{
    return d->subject;
}

QList<MimePart*> MimeMessage::parts() const
{
    QList<MimePart*> ret;
    auto content = d->content;
    if (typeid(*content) == typeid(MimeMultiPart)) {
        ret = static_cast<MimeMultiPart*>(d->content)->parts();
    } else {
        ret.append(d->content);
    }

    return ret;
}

MimeMessagePrivate::~MimeMessagePrivate()
{
    delete content;
}

QByteArray MimeMessagePrivate::encode(const QByteArray &addressKind, const QList<EmailAddress> &emails, MimePart::Encoding codec)
{
    if (emails.isEmpty()) {
        return QByteArray();
    }

    QByteArray mime = addressKind;
    bool first = true;
    for (const EmailAddress &email : emails) {
        if (!first) {
            mime.append(',');
        } else {
            first = false;
        }

        const QString name = email.name();
        if (!name.isEmpty()) {
            mime.append(MimeMessagePrivate::encodeData(codec, name, true));
            mime.append(" <" + email.address().toLatin1() + '>');
        } else {
            mime.append('<' + email.address().toLatin1() + '>');
        }
    }
    mime.append(QByteArrayLiteral("\r\n"));

    return mime;
}

QByteArray MimeMessagePrivate::encodeData(MimePart::Encoding codec, const QString &data, bool autoencoding)
{
    const QString simpleData = data.simplified();
    const QByteArray simple = simpleData.toUtf8();
    if (autoencoding) {
        if (simpleData.toLatin1() == simple) {
            return simple;
        }

        int printable = 0;
        int encoded = 0;
        const QByteArray result = QuotedPrintable::encode(simple, true, &printable, &encoded);
        int sum = printable + encoded;
        qCDebug(SIMPLEMAIL_MIMEMSG) << data << result << printable << encoded << sum << (double(printable)/sum) << (encoded/sum);
        if (sum != 0 && (double(printable)/sum) >= 0.8) {
            return " =?utf-8?Q?" + result + "?=";
        } else {
            return " =?utf-8?B?" + data.toUtf8().toBase64() + "?=";
        }
    } else {
        switch (codec) {
        case MimePart::Base64:
            return " =?utf-8?B?" + simple.toBase64() + "?=";
        case MimePart::QuotedPrintable:
            return " =?utf-8?Q?" + QuotedPrintable::encode(simple, true) + "?=";
        default:
            return ' ' + data.toLatin1();
        }
    }
}
<commit_msg>some safe checking<commit_after>/*
  Copyright (c) 2011-2012 - Tőkés Attila
  Copyright (C) 2015 Daniel Nicoletti <dantti12@gmail.com>

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

  This library 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
  Lesser General Public License for more details.

  See the LICENSE file for more details.
*/

#include "mimemessage_p.h"

#include <QtCore/QDebug>
#include "quotedprintable.h"
#include <typeinfo>

#include <QDateTime>
#include <QLoggingCategory>

Q_LOGGING_CATEGORY(SIMPLEMAIL_MIMEMSG, "simplemail.mimemessage")

using namespace SimpleMail;

MimeMessage::MimeMessage(bool createAutoMimeContent) : d(new MimeMessagePrivate)
{
    if (createAutoMimeContent) {
        d->content = new MimeMultiPart();
    }

    d->autoMimeContentCreated = createAutoMimeContent;
}

MimeMessage::MimeMessage(const MimeMessage &other) : d(other.d)
{

}

MimeMessage::~MimeMessage()
{

}

MimeMessage &MimeMessage::operator=(const MimeMessage &other)
{
    d = other.d;
    return *this;
}

MimePart& MimeMessage::getContent()
{
    return *d->content;
}

void MimeMessage::setContent(MimePart *content)
{
    if (d->autoMimeContentCreated) {
      d->autoMimeContentCreated = false;
      delete d->content;
    }
    d->content = content;
}

bool MimeMessage::write(QIODevice *device) const
{
    // Headers
    QByteArray data;

    if (!d->listExtraHeaders.isEmpty()) {
        const auto listExtraHeaders = d->listExtraHeaders;
        for (const QByteArray &header : listExtraHeaders) {
            data += MimeMessagePrivate::encodeData(d->encoding, QString::fromLatin1(header), true) + QByteArrayLiteral("\r\n");
        }
        if (device->write(data) != data.size()) {
            return false;
        }
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("From: "), QList<EmailAddress>() << d->sender, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    if (d->replyTo.address().isEmpty() == false) {
        data = MimeMessagePrivate::encode(QByteArrayLiteral("Reply-To: "), QList<EmailAddress>() << d->replyTo, d->encoding);
        if (device->write(data) != data.size()) {
            return false;
        }
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("To: "), d->recipientsTo, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("Cc: "), d->recipientsCc, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("Date: ") + QDateTime::currentDateTime().toString(Qt::RFC2822Date).toLatin1() + QByteArrayLiteral("\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("Subject: ") + MimeMessagePrivate::encodeData(d->encoding, d->subject, true);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("\r\nMIME-Version: 1.0\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    if (!d->content->write(device)) {
        qCWarning(SIMPLEMAIL_MIMEMSG) << "Failed to write MIME content";
        return false;
    }

    // Send \r\n.\r\n to end the mail data
    return device->write(QByteArrayLiteral("\r\n.\r\n")) == 5;
}

void MimeMessage::setSender(const EmailAddress &sender)
{
    d->sender = sender;
}

void MimeMessage::setToRecipients(const QList<EmailAddress> &toList)
{
    d->recipientsTo = toList;
}

QList<EmailAddress> MimeMessage::toRecipients() const
{
    return d->recipientsTo;
}

void MimeMessage::addTo(const EmailAddress &rcpt)
{
    d->recipientsTo.append(rcpt);
}

void MimeMessage::setCcRecipients(const QList<EmailAddress> &ccList)
{
    d->recipientsCc = ccList;
}

void MimeMessage::addCc(const EmailAddress &rcpt)
{
    d->recipientsCc.append(rcpt);
}

QList<EmailAddress> MimeMessage::ccRecipients() const
{
    return d->recipientsCc;
}

void MimeMessage::setBccRecipients(const QList<EmailAddress> &bccList)
{
    d->recipientsBcc = bccList;
}

QList<EmailAddress> MimeMessage::bccRecipients() const
{
    return d->recipientsBcc;
}

void MimeMessage::addBcc(const EmailAddress &rcpt)
{
    d->recipientsBcc.append(rcpt);
}

void MimeMessage::setSubject(const QString &subject)
{
    d->subject = subject;
}

void MimeMessage::addPart(MimePart *part)
{
    auto content = d->content;
    if (typeid(*content) == typeid(MimeMultiPart)) {
        static_cast<MimeMultiPart*>(d->content)->addPart(part);
    }
}

void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{
    d->encoding = hEnc;
}

void MimeMessage::addHeader(const QByteArray &headerName, const QByteArray &headerValue)
{
    d->listExtraHeaders.append(headerName + ":" + headerValue);
}

QList<QByteArray> MimeMessage::getHeaders() const
{
    return d->listExtraHeaders;
}

EmailAddress MimeMessage::sender() const
{
    return d->sender;
}

void MimeMessage::setReplyto(const EmailAddress &replyTo)
{
    d->replyTo = replyTo;
}

QString MimeMessage::subject() const
{
    return d->subject;
}

QList<MimePart*> MimeMessage::parts() const
{
    QList<MimePart*> ret;
    auto content = d->content;
    if (typeid(*content) == typeid(MimeMultiPart)) {
        ret = static_cast<MimeMultiPart*>(d->content)->parts();
    } else {
        ret.append(d->content);
    }

    return ret;
}

MimeMessagePrivate::~MimeMessagePrivate()
{
    delete content;
}

QByteArray MimeMessagePrivate::encode(const QByteArray &addressKind, const QList<EmailAddress> &emails, MimePart::Encoding codec)
{
    if (emails.isEmpty()) {
        return QByteArray();
    }

    QByteArray mime = addressKind;
    bool first = true;
    for (const EmailAddress &email : emails) {
        if (!first) {
            mime.append(',');
        } else {
            first = false;
        }

        const QString name = email.name();
        if (!name.isEmpty()) {
            mime.append(MimeMessagePrivate::encodeData(codec, name, true));
            mime.append(" <" + email.address().toLatin1() + '>');
        } else {
            mime.append('<' + email.address().toLatin1() + '>');
        }
    }
    mime.append(QByteArrayLiteral("\r\n"));

    return mime;
}

QByteArray MimeMessagePrivate::encodeData(MimePart::Encoding codec, const QString &data, bool autoencoding)
{
    const QString simpleData = data.simplified();
    const QByteArray simple = simpleData.toUtf8();
    if (autoencoding) {
        if (simpleData.toLatin1() == simple) {
            return simple;
        }

        int printable = 0;
        int encoded = 0;
        const QByteArray result = QuotedPrintable::encode(simple, true, &printable, &encoded);
        int sum = printable + encoded;
        qCDebug(SIMPLEMAIL_MIMEMSG) << data << result << printable << encoded << sum << (double(printable)/sum) << (encoded/sum);
        if (sum != 0 && (double(printable)/sum) >= 0.8) {
            return " =?utf-8?Q?" + result + "?=";
        } else {
            return " =?utf-8?B?" + data.toUtf8().toBase64() + "?=";
        }
    } else {
        switch (codec) {
        case MimePart::Base64:
            return " =?utf-8?B?" + simple.toBase64() + "?=";
        case MimePart::QuotedPrintable:
            return " =?utf-8?Q?" + QuotedPrintable::encode(simple, true) + "?=";
        default:
            return ' ' + data.toLatin1();
        }
    }
}
<|endoftext|>


<commit_before>// [WriteFile Name=ServiceFeatureTableCache, Category=Features]
// [Legal]
// Copyright 2016 Esri.

// 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.
// [Legal]

#include "ServiceFeatureTableCache.h"

#include "Map.h"
#include "MapQuickView.h"
#include "FeatureLayer.h"
#include "Basemap.h"
#include "SpatialReference.h"
#include "ServiceFeatureTable.h"
#include "Viewpoint.h"
#include "Envelope.h"
#include <QUrl>

using namespace Esri::ArcGISRuntime;

ServiceFeatureTableCache::ServiceFeatureTableCache(QQuickItem* parent) :
    QQuickItem(parent),
    m_map(nullptr),
    m_mapView(nullptr),
    m_featureLayer(nullptr),
    m_featureTable(nullptr)
{
}

ServiceFeatureTableCache::~ServiceFeatureTableCache()
{
}

void ServiceFeatureTableCache::componentComplete()
{
    QQuickItem::componentComplete();

    // find QML MapView component
    m_mapView = findChild<MapQuickView*>("mapView");
    m_mapView->setWrapAroundMode(WrapAroundMode::Disabled);

    // Create a map using the light gray canvas basemap
    m_map = new Map(Basemap::lightGrayCanvas(this), this);
    m_map->setInitialViewpoint(Viewpoint(Envelope(-13075816.4047166, 4014771.46954516, -13073005.6797177, 4016869.78617381, SpatialReference(102100))));

    // Set map to map view
    m_mapView->setMap(m_map);

    // create the feature table
    ServiceFeatureTable* m_featureTable = new ServiceFeatureTable(QUrl("http://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/FeatureServer/0"), this);

    // create the feature layer using the feature table
    m_featureLayer = new FeatureLayer(m_featureTable, this);

    // add the feature layer to the map
    m_map->operationalLayers()->append(m_featureLayer);
}
<commit_msg>removed re-declaration of the member variable and use the member instead.<commit_after>// [WriteFile Name=ServiceFeatureTableCache, Category=Features]
// [Legal]
// Copyright 2016 Esri.

// 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.
// [Legal]

#include "ServiceFeatureTableCache.h"

#include "Map.h"
#include "MapQuickView.h"
#include "FeatureLayer.h"
#include "Basemap.h"
#include "SpatialReference.h"
#include "ServiceFeatureTable.h"
#include "Viewpoint.h"
#include "Envelope.h"
#include <QUrl>

using namespace Esri::ArcGISRuntime;

ServiceFeatureTableCache::ServiceFeatureTableCache(QQuickItem* parent) :
    QQuickItem(parent),
    m_map(nullptr),
    m_mapView(nullptr),
    m_featureLayer(nullptr),
    m_featureTable(nullptr)
{
}

ServiceFeatureTableCache::~ServiceFeatureTableCache()
{
}

void ServiceFeatureTableCache::componentComplete()
{
    QQuickItem::componentComplete();

    // find QML MapView component
    m_mapView = findChild<MapQuickView*>("mapView");
    m_mapView->setWrapAroundMode(WrapAroundMode::Disabled);

    // Create a map using the light gray canvas basemap
    m_map = new Map(Basemap::lightGrayCanvas(this), this);
    m_map->setInitialViewpoint(Viewpoint(Envelope(-13075816.4047166, 4014771.46954516, -13073005.6797177, 4016869.78617381, SpatialReference(102100))));

    // Set map to map view
    m_mapView->setMap(m_map);

    // create the feature table
    m_featureTable = new ServiceFeatureTable(QUrl("http://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/FeatureServer/0"), this);

    // create the feature layer using the feature table
    m_featureLayer = new FeatureLayer(m_featureTable, this);

    // add the feature layer to the map
    m_map->operationalLayers()->append(m_featureLayer);
}
<|endoftext|>


<commit_before>#include "client.h"
#include "tests/test.h"
#include "webrequester.h"
#include "ping.h"
#include "connectiontester.h"
#include "discovery.h"
#include "network/requests/requests.h"

#include "qtquick2applicationviewer.h"

#include <QGuiApplication>
#include <QQuickView>
#include <QQmlContext>
#include <QQmlEngine>
#include <QtQml>
#include <QUrl>

#ifdef Q_OS_ANDROID
#include "statusbarhelper.h"
#include "androidimageprovider.h"
#include "androidprocessmodel.h"
#else
#include <QApplication>
#include "desktopstatusbarhelper.h"
#endif // Q_OS_ANDROID

class Time : public QObject
{
    Q_OBJECT

public:
    Time(QObject* parent = 0) : QObject(parent) {
    }

    Q_INVOKABLE int restart() {
        return time.restart();
    }

    Q_INVOKABLE int elapsed() const {
        return time.elapsed();
    }

protected:
    QTime time;
};

int main(int argc, char* argv[])
{
    QCoreApplication::setOrganizationDomain("de.hsaugsburg.informatik");
    QCoreApplication::setOrganizationName("HS Augsburg");
    QCoreApplication::setApplicationName("mPlaneClient");

#ifdef Q_OS_ANDROID
    QGuiApplication app(argc, argv);
#else
    QApplication app(argc, argv);
#endif

    qmlRegisterUncreatableType<AbstractTest>("mplane", 1, 0, "AbstractTest", "abstract class");
    qmlRegisterUncreatableType<Client>("mplane", 1, 0, "Client", "This is a singleton");
    qmlRegisterUncreatableType<TestScheduler>("mplane", 1, 0, "TestScheduler", "uncreatable type");

    // Common objects
    qmlRegisterType<TimingInformation>("mplane", 1, 0, "TimingInformation");

    // Requests
    qmlRegisterUncreatableType<Request>("mplane", 1, 0, "Request", "abstract class");
    qmlRegisterType<RegisterDeviceRequest>("mplane", 1, 0, "RegisterDeviceRequest");
    qmlRegisterType<ManualRequest>("mplane", 1, 0, "TestRequest");
    qmlRegisterType<UserRegisterRequest>("mplane", 1, 0, "UserRegisterRequest");
    qmlRegisterType<LoginRequest>("mplane", 1, 0, "LoginRequest");
    qmlRegisterType<GetConfigRequest>("mplane", 1, 0, "GetConfigRequest");

    // Responses
    qmlRegisterUncreatableType<Response>("mplane", 1, 0, "Response", "abstract class");
    qmlRegisterType<RegisterUserResponse>("mplane", 1, 0, "UserRegisterResponse");
    qmlRegisterType<LoginResponse>("mplane", 1, 0, "LoginResponse");
    qmlRegisterType<RegisterDeviceResponse>("mplane", 1, 0, "RegisterDeviceResponse");
    qmlRegisterType<GetConfigResponse>("mplane", 1, 0, "GetConfigResponse");

    qmlRegisterType<Settings>("mplane", 1, 0, "Settings");
    qmlRegisterType<WebRequester>("mplane", 1, 0, "WebRequester");
    qmlRegisterType<Ping>("mplane", 1, 0, "Ping");
    qmlRegisterType<ConnectionTester>("mplane", 1, 0, "ConnectionTester");
    qmlRegisterType<ConnectionTesterModel>("mplane", 1, 0, "ConnectionTesterModel");
    qmlRegisterType<Discovery>("mplane", 1, 0, "Discovery");
    qmlRegisterType<Time>("mplane", 1, 0, "Time");

#ifdef Q_OS_ANDROID
    qmlRegisterType<AndroidProcessModel>("mplane", 1, 0, "ProcessModel");
#endif // Q_OS_ANDROID

    QtQuick2ApplicationViewer view;

    QQmlContext* rootContext = view.rootContext();
    rootContext->setContextProperty("client", Client::instance());
#ifdef Q_OS_ANDROID
    view.engine()->addImageProvider("android", new AndroidImageProvider);
    rootContext->setContextProperty("statusBar", new StatusBarHelper(&view));
#else
    rootContext->setContextProperty("statusBar", new DesktopStatusBarHelper(&view));
#endif // Q_OS_ANDROID

    view.setMainQmlFile(QStringLiteral("qml/main.qml"));
    view.showExpanded();

    return app.exec();
}

#include "main.moc"
<commit_msg>Shutdown cleanly<commit_after>#include "client.h"
#include "tests/test.h"
#include "webrequester.h"
#include "ping.h"
#include "connectiontester.h"
#include "discovery.h"
#include "network/requests/requests.h"

#include "qtquick2applicationviewer.h"

#include <QGuiApplication>
#include <QQuickView>
#include <QQmlContext>
#include <QQmlEngine>
#include <QtQml>
#include <QUrl>

#ifdef Q_OS_ANDROID
#include "statusbarhelper.h"
#include "androidimageprovider.h"
#include "androidprocessmodel.h"
#else
#include <QApplication>
#include "desktopstatusbarhelper.h"
#endif // Q_OS_ANDROID

class Time : public QObject
{
    Q_OBJECT

public:
    Time(QObject* parent = 0) : QObject(parent) {
    }

    Q_INVOKABLE int restart() {
        return time.restart();
    }

    Q_INVOKABLE int elapsed() const {
        return time.elapsed();
    }

protected:
    QTime time;
};

int main(int argc, char* argv[])
{
    QCoreApplication::setOrganizationDomain("de.hsaugsburg.informatik");
    QCoreApplication::setOrganizationName("HS Augsburg");
    QCoreApplication::setApplicationName("mPlaneClient");

#ifdef Q_OS_ANDROID
    QGuiApplication app(argc, argv);
#else
    QApplication app(argc, argv);
    app.setQuitOnLastWindowClosed(true);
#endif

    qmlRegisterUncreatableType<AbstractTest>("mplane", 1, 0, "AbstractTest", "abstract class");
    qmlRegisterUncreatableType<Client>("mplane", 1, 0, "Client", "This is a singleton");
    qmlRegisterUncreatableType<TestScheduler>("mplane", 1, 0, "TestScheduler", "uncreatable type");

    // Common objects
    qmlRegisterType<TimingInformation>("mplane", 1, 0, "TimingInformation");

    // Requests
    qmlRegisterUncreatableType<Request>("mplane", 1, 0, "Request", "abstract class");
    qmlRegisterType<RegisterDeviceRequest>("mplane", 1, 0, "RegisterDeviceRequest");
    qmlRegisterType<ManualRequest>("mplane", 1, 0, "TestRequest");
    qmlRegisterType<UserRegisterRequest>("mplane", 1, 0, "UserRegisterRequest");
    qmlRegisterType<LoginRequest>("mplane", 1, 0, "LoginRequest");
    qmlRegisterType<GetConfigRequest>("mplane", 1, 0, "GetConfigRequest");

    // Responses
    qmlRegisterUncreatableType<Response>("mplane", 1, 0, "Response", "abstract class");
    qmlRegisterType<RegisterUserResponse>("mplane", 1, 0, "UserRegisterResponse");
    qmlRegisterType<LoginResponse>("mplane", 1, 0, "LoginResponse");
    qmlRegisterType<RegisterDeviceResponse>("mplane", 1, 0, "RegisterDeviceResponse");
    qmlRegisterType<GetConfigResponse>("mplane", 1, 0, "GetConfigResponse");

    qmlRegisterType<Settings>("mplane", 1, 0, "Settings");
    qmlRegisterType<WebRequester>("mplane", 1, 0, "WebRequester");
    qmlRegisterType<Ping>("mplane", 1, 0, "Ping");
    qmlRegisterType<ConnectionTester>("mplane", 1, 0, "ConnectionTester");
    qmlRegisterType<ConnectionTesterModel>("mplane", 1, 0, "ConnectionTesterModel");
    qmlRegisterType<Discovery>("mplane", 1, 0, "Discovery");
    qmlRegisterType<Time>("mplane", 1, 0, "Time");

#ifdef Q_OS_ANDROID
    qmlRegisterType<AndroidProcessModel>("mplane", 1, 0, "ProcessModel");
#endif // Q_OS_ANDROID

    QtQuick2ApplicationViewer view;

    QQmlContext* rootContext = view.rootContext();
    rootContext->setContextProperty("client", Client::instance());
#ifdef Q_OS_ANDROID
    view.engine()->addImageProvider("android", new AndroidImageProvider);
    rootContext->setContextProperty("statusBar", new StatusBarHelper(&view));
#else
    rootContext->setContextProperty("statusBar", new DesktopStatusBarHelper(&view));
#endif // Q_OS_ANDROID

    view.setMainQmlFile(QStringLiteral("qml/main.qml"));
    view.showExpanded();

    int returnCode = app.exec();

    // Cleanly shutdown
    Client::instance()->deleteLater();
    QTimer::singleShot(1, &app, SLOT(quit()));
    app.exec();

    return returnCode;
}

#include "main.moc"
<|endoftext|>


<commit_before>/** \file   PdfUtil.cc
 *  \brief  Implementation of functions relating to PDF documents.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2015,2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "PdfUtil.h"
#include <leptonica/allheaders.h>
#include <tesseract/baseapi.h>
#include "ExecUtil.h"
#include "FileUtil.h"
#include "StringUtil.h"
#include "util.h"

namespace PdfUtil {

bool ExtractText(const std::string &pdf_document, std::string * const extracted_text) {
    static std::string pdftotext_path;
    if (pdftotext_path.empty())
        pdftotext_path = ExecUtil::LocateOrDie("pdftotext");

    const FileUtil::AutoTempFile auto_temp_file1;
    const std::string &input_filename(auto_temp_file1.getFilePath());
    if (not FileUtil::WriteString(input_filename, pdf_document)) {
        LOG_WARNING("can't write document to \"" + input_filename + "\"!");
        return false;
    }

    const FileUtil::AutoTempFile auto_temp_file2;
    const std::string &output_filename(auto_temp_file2.getFilePath());

    const int retval(ExecUtil::Exec(pdftotext_path,
                                    { "-enc", "UTF-8", "-nopgbrk", input_filename, output_filename }));
    if (retval != 0) {
        LOG_WARNING("failed to execute \"" + pdftotext_path + "\"!");
        return false;
    }

    if (not FileUtil::ReadString(output_filename, extracted_text)) {
        LOG_WARNING("failed to read extracted text from \"" + output_filename + "\"!");
        return false;
    }

    return not extracted_text->empty();
}

bool PdfFileContainsNoText(const std::string &path) {
    static std::string pdffonts_path;
    if (pdffonts_path.empty())
        pdffonts_path = ExecUtil::LocateOrDie("pdffonts");

    const FileUtil::AutoTempFile auto_temp_file;
    const std::string &output_filename(auto_temp_file.getFilePath());
    const int retval(ExecUtil::Exec(pdffonts_path, { path }, "", output_filename));
    if (retval == 0) {
        std::string output;
        if (not FileUtil::ReadString(output_filename, &output))
            return false;
        return output.length() == 188; // Header only?
    }

    return retval == 0;
}

bool PdfDocContainsNoText(const std::string &document) {
    const FileUtil::AutoTempFile auto_temp_file;
    const std::string &output_filename(auto_temp_file.getFilePath());
    if (not FileUtil::WriteString(output_filename, document))
        return false;
    return PdfFileContainsNoText(output_filename);
}

bool GetTextFromImage(const std::string &img_path, const std::string &tesseract_language_code,
                      std::string * const extracted_text)
{
    tesseract::TessBaseAPI * const api(new tesseract::TessBaseAPI());
    if (api->Init(nullptr, tesseract_language_code.c_str())) {
        LOG_WARNING("Could not initialize Tesseract API!");
        return false;
    }

    Pix *image(pixRead(img_path.c_str()));
    api->SetImage(image);

    char *utf8_text(api->GetUTF8Text());
    *extracted_text = utf8_text;
    delete[] utf8_text;

    api->End();
    delete api;
    pixDestroy(&image);
    delete image;

    return not extracted_text->empty();
}

bool GetTextFromImagePDF(const std::string &pdf_document, const std::string &tesseract_language_code,
                         std::string * const extracted_text, unsigned timeout)
{
    extracted_text->clear();

    static std::string pdf_images_script_path(ExecUtil::LocateOrDie("pdfimages"));

    const FileUtil::AutoTempDirectory auto_temp_dir;
    const std::string &output_dirname(auto_temp_dir.getDirectoryPath());
    const std::string input_filename(output_dirname + "/in.pdf");
    if (not FileUtil::WriteString(input_filename, pdf_document)) {
        LOG_WARNING("failed to write the PDF to a temp file!");
        return false;
    }

    if (ExecUtil::Exec(pdf_images_script_path, { input_filename, output_dirname + "/out" }, "", "", "", timeout) != 0) {
        LOG_WARNING("failed to extract images from PDF file!");
        return false;
    }

    std::vector<std::string> pdf_image_filenames;
    if (FileUtil::GetFileNameList("out.*", &pdf_image_filenames, output_dirname) == 0) {
        LOG_WARNING("PDF did not contain any images!");
        return false;
    }

    for (const std::string &pdf_image_filename : pdf_image_filenames) {
        std::string image_text;
        if (not GetTextFromImage(output_dirname + "/" + pdf_image_filename, tesseract_language_code, &image_text)) {
            LOG_WARNING("failed to extract text from image " + pdf_image_filename);
            return false;
        }
         *extracted_text += " " + image_text;
    }

    *extracted_text = StringUtil::TrimWhite(*extracted_text);
    return not extracted_text->empty();
}

bool GetOCRedTextFromPDF(const std::string &pdf_document_path, const std::string &tesseract_language_code,
                         std::string * const extracted_text, unsigned timeout) {
    extracted_text->clear();
    static std::string pdf_to_image_command(ExecUtil::LocateOrDie("convert"));
    const FileUtil::AutoTempDirectory auto_temp_dir;
    const std::string &image_dirname(auto_temp_dir.getDirectoryPath());
    const std::string temp_image_location = image_dirname + "/img.tiff";
    if (ExecUtil::Exec(pdf_to_image_command, { "-density", "300", pdf_document_path, "-depth", "8", "-strip" ,
                                               "-background", "white", "-alpha", "off", temp_image_location
                                             }, "", "", "", timeout) != 0) {
        LOG_WARNING("failed to convert PDF to image!");
        return false;
    }
    if (not GetTextFromImage(temp_image_location, tesseract_language_code, extracted_text))
        LOG_WARNING("failed to extract OCRed text");

    *extracted_text = StringUtil::TrimWhite(*extracted_text);
    return not extracted_text->empty();
}

} // namespace PdfUtil
<commit_msg>Add support for multipage tiffs in OCR handling<commit_after>/** \file   PdfUtil.cc
 *  \brief  Implementation of functions relating to PDF documents.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2015,2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "PdfUtil.h"
#include <leptonica/allheaders.h>
#include <tesseract/baseapi.h>
#include "ExecUtil.h"
#include "FileUtil.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "util.h"

namespace PdfUtil {

bool ExtractText(const std::string &pdf_document, std::string * const extracted_text) {
    static std::string pdftotext_path;
    if (pdftotext_path.empty())
        pdftotext_path = ExecUtil::LocateOrDie("pdftotext");

    const FileUtil::AutoTempFile auto_temp_file1;
    const std::string &input_filename(auto_temp_file1.getFilePath());
    if (not FileUtil::WriteString(input_filename, pdf_document)) {
        LOG_WARNING("can't write document to \"" + input_filename + "\"!");
        return false;
    }

    const FileUtil::AutoTempFile auto_temp_file2;
    const std::string &output_filename(auto_temp_file2.getFilePath());

    const int retval(ExecUtil::Exec(pdftotext_path,
                                    { "-enc", "UTF-8", "-nopgbrk", input_filename, output_filename }));
    if (retval != 0) {
        LOG_WARNING("failed to execute \"" + pdftotext_path + "\"!");
        return false;
    }

    if (not FileUtil::ReadString(output_filename, extracted_text)) {
        LOG_WARNING("failed to read extracted text from \"" + output_filename + "\"!");
        return false;
    }

    return not extracted_text->empty();
}

bool PdfFileContainsNoText(const std::string &path) {
    static std::string pdffonts_path;
    if (pdffonts_path.empty())
        pdffonts_path = ExecUtil::LocateOrDie("pdffonts");

    const FileUtil::AutoTempFile auto_temp_file;
    const std::string &output_filename(auto_temp_file.getFilePath());
    const int retval(ExecUtil::Exec(pdffonts_path, { path }, "", output_filename));
    if (retval == 0) {
        std::string output;
        if (not FileUtil::ReadString(output_filename, &output))
            return false;
        return output.length() == 188; // Header only?
    }

    return retval == 0;
}

bool PdfDocContainsNoText(const std::string &document) {
    const FileUtil::AutoTempFile auto_temp_file;
    const std::string &output_filename(auto_temp_file.getFilePath());
    if (not FileUtil::WriteString(output_filename, document))
        return false;
    return PdfFileContainsNoText(output_filename);
}

bool GetTextFromImage(const std::string &img_path, const std::string &tesseract_language_code,
                      std::string * const extracted_text)
{
    tesseract::TessBaseAPI * const api(new tesseract::TessBaseAPI());
    if (api->Init(nullptr, tesseract_language_code.c_str())) {
        LOG_WARNING("Could not initialize Tesseract API!");
        return false;
    }

    const std::string filetype(MediaTypeUtil::GetFileMediaType(img_path));

    // Special Handling for tiff multipages
    if (filetype == "image/tiff") {
        extracted_text->clear();
        Pixa *multipage_image(pixaReadMultipageTiff(img_path.c_str()));
        for (l_int32 offset(0); offset < multipage_image->n; ++offset) {
             LOG_INFO("Extracting page " + std::to_string(offset + 1));
             api->SetImage(multipage_image->pix[offset]);
             char *utf8_page(api->GetUTF8Text());
             extracted_text->append(utf8_page);
             delete[] utf8_page;
        }
        api->End();
        delete api;
        pixaDestroy(&multipage_image);
        delete multipage_image;

    } else {
        Pix *image(pixRead(img_path.c_str()));
        api->SetImage(image);
        char *utf8_text(api->GetUTF8Text());
        *extracted_text = utf8_text;
        delete[] utf8_text;
        api->End();
        delete api;
        pixDestroy(&image);
        delete image;

    }
    return not extracted_text->empty();
}

bool GetTextFromImagePDF(const std::string &pdf_document, const std::string &tesseract_language_code,
                         std::string * const extracted_text, unsigned timeout)
{
    extracted_text->clear();

    static std::string pdf_images_script_path(ExecUtil::LocateOrDie("pdfimages"));

    const FileUtil::AutoTempDirectory auto_temp_dir;
    const std::string &output_dirname(auto_temp_dir.getDirectoryPath());
    const std::string input_filename(output_dirname + "/in.pdf");
    if (not FileUtil::WriteString(input_filename, pdf_document)) {
        LOG_WARNING("failed to write the PDF to a temp file!");
        return false;
    }

    if (ExecUtil::Exec(pdf_images_script_path, { input_filename, output_dirname + "/out" }, "", "", "", timeout) != 0) {
        LOG_WARNING("failed to extract images from PDF file!");
        return false;
    }

    std::vector<std::string> pdf_image_filenames;
    if (FileUtil::GetFileNameList("out.*", &pdf_image_filenames, output_dirname) == 0) {
        LOG_WARNING("PDF did not contain any images!");
        return false;
    }

    for (const std::string &pdf_image_filename : pdf_image_filenames) {
        std::string image_text;
        if (not GetTextFromImage(output_dirname + "/" + pdf_image_filename, tesseract_language_code, &image_text)) {
            LOG_WARNING("failed to extract text from image " + pdf_image_filename);
            return false;
        }
         *extracted_text += " " + image_text;
    }

    *extracted_text = StringUtil::TrimWhite(*extracted_text);
    return not extracted_text->empty();
}

bool GetOCRedTextFromPDF(const std::string &pdf_document_path, const std::string &tesseract_language_code,
                         std::string * const extracted_text, unsigned timeout) {
    extracted_text->clear();
    static std::string pdf_to_image_command(ExecUtil::LocateOrDie("convert"));
    const FileUtil::AutoTempDirectory auto_temp_dir;
    const std::string &image_dirname(auto_temp_dir.getDirectoryPath());
    (void) &image_dirname;
    const std::string temp_image_location = image_dirname + "/img.tiff";
    if (ExecUtil::Exec(pdf_to_image_command, { "-density", "300", pdf_document_path, "-depth", "8", "-strip",
                                               "-background", "white", "-alpha", "off", temp_image_location
                                             }, "", "", "", timeout) != 0) {
        LOG_WARNING("failed to convert PDF to image!");
        return false;
    }
    if (not GetTextFromImage(temp_image_location, tesseract_language_code, extracted_text))
        LOG_WARNING("failed to extract OCRed text");

    *extracted_text = StringUtil::TrimWhite(*extracted_text);
    return not extracted_text->empty();
}

} // namespace PdfUtil
<|endoftext|>


<commit_before>/* This file is part of the CivetWeb web server.
 * See https://github.com/civetweb/civetweb/
 * (C) 2015 by the CivetWeb authors, MIT license.
 */

#include "duktape.h"

/* TODO: the mg context should be added to duktape as well */
/* Alternative: redefine a new, clean API from scratch (instead of using mg),
 * or at least do not add problematic functions. */
/* For evaluation purposes, currently only "send" is supported.
 * All other ~50 functions will be added later. */

/* Note: This is only experimental support, so any API may still change. */

static const char *civetweb_conn_id = "\xFF"
                                      "civetweb_conn";

static void *
mg_duk_mem_alloc(void *udata, duk_size_t size)
{
	return mg_malloc(size);
}

static void *
mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
{
	return mg_realloc(ptr, newsize);
}

static void
mg_duk_mem_free(void *udata, void *ptr)
{
	mg_free(ptr);
}

static void
mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
{
	/* TODO: check if this handler is required - duk_peval_file probably
	 * already avoids that this function is called. */
	/* TODO: test this handler (if it is called) */
	struct mg_connection *conn;

	duk_push_global_stash(ctx);
	duk_get_prop_string(ctx, -1, civetweb_conn_id);
	conn = (struct mg_connection *)duk_to_pointer(ctx, -1);

	mg_cry(conn, "%s", msg);
}

static duk_ret_t
duk_itf_write(duk_context *ctx)
{
	struct mg_connection *conn;
	duk_double_t ret;
	duk_size_t len = 0;
	const char *val = duk_require_lstring(ctx, -1, &len);

	/*
	    duk_push_global_stash(ctx);
	    duk_get_prop_string(ctx, -1, civetweb_conn_id);
	    conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
	*/
	duk_push_current_function(ctx);
	duk_get_prop_string(ctx, -1, civetweb_conn_id);
	conn = (struct mg_connection *)duk_to_pointer(ctx, -1);

	if (!conn) {
		duk_error(ctx,
		          DUK_ERR_INTERNAL_ERROR,
		          "function not available without connection object");
		/* probably never reached, but satisfies static code analysis */
		return DUK_RET_INTERNAL_ERROR;
	}

	ret = mg_write(conn, val, len);

	duk_push_number(ctx, ret);
	return 1;
}

static duk_ret_t
duk_itf_read(duk_context *ctx)
{
	struct mg_connection *conn;
	char buf[1024];
	int len;

	duk_push_global_stash(ctx);
	duk_get_prop_string(ctx, -1, civetweb_conn_id);
	conn = (struct mg_connection *)duk_to_pointer(ctx, -1);

	if (!conn) {
		duk_error(ctx,
		          DUK_ERR_INTERNAL_ERROR,
		          "function not available without connection object");
		/* probably never reached, but satisfies static code analysis */
		return DUK_RET_INTERNAL_ERROR;
	}

	len = mg_read(conn, buf, sizeof(buf));

	duk_push_lstring(ctx, buf, len);
	return 1;
}

static void
mg_exec_duktape_script(struct mg_connection *conn, const char *path)
{
	duk_context *ctx = NULL;

	conn->must_close = 1;

	/* Create Duktape interpreter state */
	ctx = duk_create_heap(mg_duk_mem_alloc,
	                      mg_duk_mem_realloc,
	                      mg_duk_mem_free,
	                      NULL,
	                      mg_duk_fatal_handler);
	if (!ctx) {
		mg_cry(conn, "Failed to create a Duktape heap.");
		goto exec_duktape_finished;
	}

	/* Add "conn" object */
	duk_push_global_object(ctx);
	duk_push_object(ctx); /* create a new table/object ("conn") */

	duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
	duk_push_pointer(ctx, (void *)conn);
	duk_put_prop_string(ctx, -2, civetweb_conn_id);
	duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */

	duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
	duk_push_pointer(ctx, (void *)conn);
	duk_put_prop_string(ctx, -2, civetweb_conn_id);
	duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */

	duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */

	duk_push_global_stash(ctx);
	duk_push_pointer(ctx, (void *)conn);
	duk_put_prop_string(ctx, -2, civetweb_conn_id);

	if (duk_peval_file(ctx, path) != 0) {
		mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
		goto exec_duktape_finished;
	}
	duk_pop(ctx); /* ignore result */

exec_duktape_finished:
	duk_destroy_heap(ctx);
}
<commit_msg>Duktape: Add connection string properties<commit_after>/* This file is part of the CivetWeb web server.
 * See https://github.com/civetweb/civetweb/
 * (C) 2015 by the CivetWeb authors, MIT license.
 */

#include "duktape.h"

/* TODO: the mg context should be added to duktape as well */
/* Alternative: redefine a new, clean API from scratch (instead of using mg),
 * or at least do not add problematic functions. */
/* For evaluation purposes, currently only "send" is supported.
 * All other ~50 functions will be added later. */

/* Note: This is only experimental support, so any API may still change. */

static const char *civetweb_conn_id = "\xFF"
                                      "civetweb_conn";

static void *
mg_duk_mem_alloc(void *udata, duk_size_t size)
{
	return mg_malloc(size);
}

static void *
mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
{
	return mg_realloc(ptr, newsize);
}

static void
mg_duk_mem_free(void *udata, void *ptr)
{
	mg_free(ptr);
}

static void
mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
{
	/* TODO: check if this handler is required - duk_peval_file probably
	 * already avoids that this function is called. */
	/* TODO: test this handler (if it is called) */
	struct mg_connection *conn;

	duk_push_global_stash(ctx);
	duk_get_prop_string(ctx, -1, civetweb_conn_id);
	conn = (struct mg_connection *)duk_to_pointer(ctx, -1);

	mg_cry(conn, "%s", msg);
}

static duk_ret_t
duk_itf_write(duk_context *ctx)
{
	struct mg_connection *conn;
	duk_double_t ret;
	duk_size_t len = 0;
	const char *val = duk_require_lstring(ctx, -1, &len);

	/*
	    duk_push_global_stash(ctx);
	    duk_get_prop_string(ctx, -1, civetweb_conn_id);
	    conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
	*/
	duk_push_current_function(ctx);
	duk_get_prop_string(ctx, -1, civetweb_conn_id);
	conn = (struct mg_connection *)duk_to_pointer(ctx, -1);

	if (!conn) {
		duk_error(ctx,
		          DUK_ERR_INTERNAL_ERROR,
		          "function not available without connection object");
		/* probably never reached, but satisfies static code analysis */
		return DUK_RET_INTERNAL_ERROR;
	}

	ret = mg_write(conn, val, len);

	duk_push_number(ctx, ret);
	return 1;
}

static duk_ret_t
duk_itf_read(duk_context *ctx)
{
	struct mg_connection *conn;
	char buf[1024];
	int len;

	duk_push_global_stash(ctx);
	duk_get_prop_string(ctx, -1, civetweb_conn_id);
	conn = (struct mg_connection *)duk_to_pointer(ctx, -1);

	if (!conn) {
		duk_error(ctx,
		          DUK_ERR_INTERNAL_ERROR,
		          "function not available without connection object");
		/* probably never reached, but satisfies static code analysis */
		return DUK_RET_INTERNAL_ERROR;
	}

	len = mg_read(conn, buf, sizeof(buf));

	duk_push_lstring(ctx, buf, len);
	return 1;
}

static void
mg_exec_duktape_script(struct mg_connection *conn, const char *path)
{
	duk_context *ctx = NULL;

	conn->must_close = 1;

	/* Create Duktape interpreter state */
	ctx = duk_create_heap(mg_duk_mem_alloc,
	                      mg_duk_mem_realloc,
	                      mg_duk_mem_free,
	                      NULL,
	                      mg_duk_fatal_handler);
	if (!ctx) {
		mg_cry(conn, "Failed to create a Duktape heap.");
		goto exec_duktape_finished;
	}

	/* Add "conn" object */
	duk_push_global_object(ctx);
	duk_push_object(ctx); /* create a new table/object ("conn") */

	duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
	duk_push_pointer(ctx, (void *)conn);
	duk_put_prop_string(ctx, -2, civetweb_conn_id);
	duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */

	duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
	duk_push_pointer(ctx, (void *)conn);
	duk_put_prop_string(ctx, -2, civetweb_conn_id);
	duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */

	duk_push_string(ctx, conn->request_info.request_method);
	duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... */

	duk_push_string(ctx, conn->request_info.request_uri);
	duk_put_prop_string(ctx, -2, "request_uri");

	duk_push_string(ctx, conn->request_info.local_uri);
	duk_put_prop_string(ctx, -2, "uri");

	duk_push_string(ctx, conn->request_info.http_version);
	duk_put_prop_string(ctx, -2, "http_version");

	duk_push_string(ctx, conn->request_info.query_string);
	duk_put_prop_string(ctx, -2, "query_string");

	duk_push_string(ctx, conn->request_info.remote_addr);
	duk_put_prop_string(ctx, -2, "remote_addr");

	duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */

	duk_push_global_stash(ctx);
	duk_push_pointer(ctx, (void *)conn);
	duk_put_prop_string(ctx, -2, civetweb_conn_id);

	if (duk_peval_file(ctx, path) != 0) {
		mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
		goto exec_duktape_finished;
	}
	duk_pop(ctx); /* ignore result */

exec_duktape_finished:
	duk_destroy_heap(ctx);
}
<|endoftext|>


<commit_before>//
//  yas_task.cpp
//

#include "yas_task.h"
#include <atomic>
#include <deque>
#include <mutex>
#include <thread>
#include <vector>
#include "yas_stl_utils.h"

using namespace yas;

#pragma mark - task

task::task(execution_f const &execution, task_option_t &&option)
    : _canceled(false), _execution(execution), _option(std::move(option)) {
}

task::task(execution_f &&execution, task_option_t &&option)
    : _canceled(false), _execution(std::move(execution)), _option(std::move(option)) {
}

void task::cancel() {
    this->_canceled = true;
}

bool task::is_canceled() const {
    return this->_canceled;
}

task_option_t const &task::option() const {
    return this->_option;
}

std::shared_ptr<controllable_task> task::controllable() {
    return std::dynamic_pointer_cast<controllable_task>(shared_from_this());
}

void task::execute() {
    if (!this->is_canceled()) {
        if (auto &execution = this->_execution) {
            execution(*this);
        }
    }
}

std::shared_ptr<task> yas::make_task(task::execution_f const &execution, task_option_t opt) {
    return std::shared_ptr<task>(new task{execution, std::move(opt)});
}

std::shared_ptr<task> yas::make_task(task::execution_f &&execution, task_option_t opt) {
    return std::shared_ptr<task>(new task{std::move(execution), std::move(opt)});
}

#pragma mark - queue

class task_queue::impl : public base::impl {
   public:
    impl(std::size_t const count) : _tasks(count) {
    }

    ~impl() {
        this->cancel();
    }

    void push_back(std::shared_ptr<task> &&task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        auto &cancel_id = task->option().push_cancel_id;

        for (auto &deque : this->_tasks) {
            erase_if(deque, [&cancel_id](auto const &value) { return value->option().push_cancel_id == cancel_id; });
        }

        if (this->_current_task) {
            if (this->_current_task->option().push_cancel_id == cancel_id) {
                this->_current_task->cancel();
            }
        }

        auto &deque = this->_tasks.at(task->option().priority);
        deque.emplace_back(std::move(task));

        this->_start_next_task_if_needed();
    }

    void push_front(std::shared_ptr<task> &&task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        auto &cancel_id = task->option().push_cancel_id;

        for (auto &deque : this->_tasks) {
            erase_if(deque, [&cancel_id](auto const &value) { return value->option().push_cancel_id == cancel_id; });
        }

        if (this->_current_task) {
            if (this->_current_task->option().push_cancel_id == cancel_id) {
                this->_current_task->cancel();
            }
        }

        auto &deque = this->_tasks.at(task->option().priority);
        deque.emplace_front(std::move(task));

        this->_start_next_task_if_needed();
    }

    void cancel(std::shared_ptr<task> const &canceling_task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        for (auto &deque : this->_tasks) {
            for (auto &task : deque) {
                if (canceling_task == task) {
                    task->cancel();
                }
            }
        }

        if (this->_current_task) {
            if (this->_current_task == canceling_task) {
                this->_current_task->cancel();
            }
        }
    }

    void cancel_for_id(base const &cancel_id) {
        this->cancel([&cancel_id](base const &target_cancel_id) { return cancel_id == target_cancel_id; });
    }

    void cancel(cancellation_f const &cancellation) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        for (auto &deque : this->_tasks) {
            erase_if(deque, [&cancellation](auto const &value) { return cancellation(value->option().cancel_id); });
        }

        if (this->_current_task) {
            if (cancellation(this->_current_task->option().cancel_id)) {
                this->_current_task->cancel();
            }
        }
    }

    void cancel() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        for (auto &deque : this->_tasks) {
            for (auto &task : deque) {
                task->cancel();
            }
            deque.clear();
        }

        if (this->_current_task) {
            this->_current_task->cancel();
        }
    }

    void wait_until_all_tasks_are_finished() {
        while (true) {
            std::lock_guard<std::recursive_mutex> lock(this->_mutex);

            bool task_exists = this->_current_task != nullptr;
            if (!task_exists) {
                for (auto &deque : this->_tasks) {
                    if (deque.size() > 0) {
                        task_exists = true;
                    }
                }
            }

            if (task_exists) {
                if (this->_suspended) {
                    throw "task_queue is suspended.";
                }
                std::this_thread::yield();
            } else {
                break;
            }
        }
    }

    void suspend() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        this->_suspended = true;
    }

    void resume() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (this->_suspended) {
            this->_suspended = false;
            this->_start_next_task_if_needed();
        }
    }

    std::size_t priority_count() const {
        return this->_tasks.size();
    }

    bool is_suspended() const {
        return this->_suspended;
    }

    bool is_operating() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (this->_current_task) {
            return true;
        }

        for (auto const &deque : this->_tasks) {
            if (deque.size() > 0) {
                return true;
            }
        }

        return false;
    }

   private:
    std::shared_ptr<task> _current_task = nullptr;
    std::vector<std::deque<std::shared_ptr<task>>> _tasks;
    bool _suspended = false;
    mutable std::recursive_mutex _mutex;

    void _start_next_task_if_needed() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (!this->_current_task && !this->_suspended) {
            std::shared_ptr<task> task{nullptr};

            for (auto &deque : this->_tasks) {
                if (!deque.empty()) {
                    task = deque.front();
                    deque.pop_front();
                    break;
                }
            }

            if (task) {
                this->_current_task = task;

                std::thread thread{[weak_task = to_weak(task), weak_queue = to_weak(cast<task_queue>())]() {
                    auto task = weak_task.lock();
                    if (task) {
                        task->controllable()->execute();

                        if (auto queue = weak_queue.lock()) {
                            queue.impl_ptr<impl>()->_task_did_finish(task);
                        }
                    }
                }};

                thread.detach();
            }
        }
    }

    void _task_did_finish(std::shared_ptr<task> const &pre_task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (this->_current_task == pre_task) {
            this->_current_task = nullptr;
        }

        this->_start_next_task_if_needed();
    }
};

task_queue::task_queue(std::size_t const count) : base(std::make_unique<impl>(count)) {
}

task_queue::task_queue(std::nullptr_t) : base(nullptr) {
}

void task_queue::push_back(task &task) {
    impl_ptr<impl>()->push_back(task.shared_from_this());
}

void task_queue::push_front(task &task) {
    impl_ptr<impl>()->push_front(task.shared_from_this());
}

void task_queue::cancel(task &task) {
    impl_ptr<impl>()->cancel(task.shared_from_this());
}

void task_queue::cancel_for_id(base const &identifier) {
    impl_ptr<impl>()->cancel_for_id(identifier);
}

void task_queue::cancel(cancellation_f const &cancellation) {
    impl_ptr<impl>()->cancel(cancellation);
}

void task_queue::cancel_all() {
    impl_ptr<impl>()->cancel();
}

void task_queue::wait_until_all_tasks_are_finished() {
    impl_ptr<impl>()->wait_until_all_tasks_are_finished();
}

void task_queue::suspend() {
    impl_ptr<impl>()->suspend();
}

void task_queue::resume() {
    impl_ptr<impl>()->resume();
}

std::size_t task_queue::priority_count() const {
    return impl_ptr<impl>()->priority_count();
}

bool task_queue::is_suspended() const {
    return impl_ptr<impl>()->is_suspended();
}

bool task_queue::is_operating() const {
    return impl_ptr<impl>()->is_operating();
}
<commit_msg>struct<commit_after>//
//  yas_task.cpp
//

#include "yas_task.h"
#include <atomic>
#include <deque>
#include <mutex>
#include <thread>
#include <vector>
#include "yas_stl_utils.h"

using namespace yas;

#pragma mark - task

task::task(execution_f const &execution, task_option_t &&option)
    : _canceled(false), _execution(execution), _option(std::move(option)) {
}

task::task(execution_f &&execution, task_option_t &&option)
    : _canceled(false), _execution(std::move(execution)), _option(std::move(option)) {
}

void task::cancel() {
    this->_canceled = true;
}

bool task::is_canceled() const {
    return this->_canceled;
}

task_option_t const &task::option() const {
    return this->_option;
}

std::shared_ptr<controllable_task> task::controllable() {
    return std::dynamic_pointer_cast<controllable_task>(shared_from_this());
}

void task::execute() {
    if (!this->is_canceled()) {
        if (auto &execution = this->_execution) {
            execution(*this);
        }
    }
}

std::shared_ptr<task> yas::make_task(task::execution_f const &execution, task_option_t opt) {
    return std::shared_ptr<task>(new task{execution, std::move(opt)});
}

std::shared_ptr<task> yas::make_task(task::execution_f &&execution, task_option_t opt) {
    return std::shared_ptr<task>(new task{std::move(execution), std::move(opt)});
}

#pragma mark - queue

struct task_queue::impl : base::impl {
    impl(std::size_t const count) : _tasks(count) {
    }

    ~impl() {
        this->cancel();
    }

    void push_back(std::shared_ptr<task> &&task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        auto &cancel_id = task->option().push_cancel_id;

        for (auto &deque : this->_tasks) {
            erase_if(deque, [&cancel_id](auto const &value) { return value->option().push_cancel_id == cancel_id; });
        }

        if (this->_current_task) {
            if (this->_current_task->option().push_cancel_id == cancel_id) {
                this->_current_task->cancel();
            }
        }

        auto &deque = this->_tasks.at(task->option().priority);
        deque.emplace_back(std::move(task));

        this->_start_next_task_if_needed();
    }

    void push_front(std::shared_ptr<task> &&task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        auto &cancel_id = task->option().push_cancel_id;

        for (auto &deque : this->_tasks) {
            erase_if(deque, [&cancel_id](auto const &value) { return value->option().push_cancel_id == cancel_id; });
        }

        if (this->_current_task) {
            if (this->_current_task->option().push_cancel_id == cancel_id) {
                this->_current_task->cancel();
            }
        }

        auto &deque = this->_tasks.at(task->option().priority);
        deque.emplace_front(std::move(task));

        this->_start_next_task_if_needed();
    }

    void cancel(std::shared_ptr<task> const &canceling_task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        for (auto &deque : this->_tasks) {
            for (auto &task : deque) {
                if (canceling_task == task) {
                    task->cancel();
                }
            }
        }

        if (this->_current_task) {
            if (this->_current_task == canceling_task) {
                this->_current_task->cancel();
            }
        }
    }

    void cancel_for_id(base const &cancel_id) {
        this->cancel([&cancel_id](base const &target_cancel_id) { return cancel_id == target_cancel_id; });
    }

    void cancel(cancellation_f const &cancellation) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        for (auto &deque : this->_tasks) {
            erase_if(deque, [&cancellation](auto const &value) { return cancellation(value->option().cancel_id); });
        }

        if (this->_current_task) {
            if (cancellation(this->_current_task->option().cancel_id)) {
                this->_current_task->cancel();
            }
        }
    }

    void cancel() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        for (auto &deque : this->_tasks) {
            for (auto &task : deque) {
                task->cancel();
            }
            deque.clear();
        }

        if (this->_current_task) {
            this->_current_task->cancel();
        }
    }

    void wait_until_all_tasks_are_finished() {
        while (true) {
            std::lock_guard<std::recursive_mutex> lock(this->_mutex);

            bool task_exists = this->_current_task != nullptr;
            if (!task_exists) {
                for (auto &deque : this->_tasks) {
                    if (deque.size() > 0) {
                        task_exists = true;
                    }
                }
            }

            if (task_exists) {
                if (this->_suspended) {
                    throw "task_queue is suspended.";
                }
                std::this_thread::yield();
            } else {
                break;
            }
        }
    }

    void suspend() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        this->_suspended = true;
    }

    void resume() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (this->_suspended) {
            this->_suspended = false;
            this->_start_next_task_if_needed();
        }
    }

    std::size_t priority_count() const {
        return this->_tasks.size();
    }

    bool is_suspended() const {
        return this->_suspended;
    }

    bool is_operating() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (this->_current_task) {
            return true;
        }

        for (auto const &deque : this->_tasks) {
            if (deque.size() > 0) {
                return true;
            }
        }

        return false;
    }

   private:
    std::shared_ptr<task> _current_task = nullptr;
    std::vector<std::deque<std::shared_ptr<task>>> _tasks;
    bool _suspended = false;
    mutable std::recursive_mutex _mutex;

    void _start_next_task_if_needed() {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (!this->_current_task && !this->_suspended) {
            std::shared_ptr<task> task{nullptr};

            for (auto &deque : this->_tasks) {
                if (!deque.empty()) {
                    task = deque.front();
                    deque.pop_front();
                    break;
                }
            }

            if (task) {
                this->_current_task = task;

                std::thread thread{[weak_task = to_weak(task), weak_queue = to_weak(cast<task_queue>())]() {
                    auto task = weak_task.lock();
                    if (task) {
                        task->controllable()->execute();

                        if (auto queue = weak_queue.lock()) {
                            queue.impl_ptr<impl>()->_task_did_finish(task);
                        }
                    }
                }};

                thread.detach();
            }
        }
    }

    void _task_did_finish(std::shared_ptr<task> const &pre_task) {
        std::lock_guard<std::recursive_mutex> lock(this->_mutex);

        if (this->_current_task == pre_task) {
            this->_current_task = nullptr;
        }

        this->_start_next_task_if_needed();
    }
};

task_queue::task_queue(std::size_t const count) : base(std::make_unique<impl>(count)) {
}

task_queue::task_queue(std::nullptr_t) : base(nullptr) {
}

void task_queue::push_back(task &task) {
    impl_ptr<impl>()->push_back(task.shared_from_this());
}

void task_queue::push_front(task &task) {
    impl_ptr<impl>()->push_front(task.shared_from_this());
}

void task_queue::cancel(task &task) {
    impl_ptr<impl>()->cancel(task.shared_from_this());
}

void task_queue::cancel_for_id(base const &identifier) {
    impl_ptr<impl>()->cancel_for_id(identifier);
}

void task_queue::cancel(cancellation_f const &cancellation) {
    impl_ptr<impl>()->cancel(cancellation);
}

void task_queue::cancel_all() {
    impl_ptr<impl>()->cancel();
}

void task_queue::wait_until_all_tasks_are_finished() {
    impl_ptr<impl>()->wait_until_all_tasks_are_finished();
}

void task_queue::suspend() {
    impl_ptr<impl>()->suspend();
}

void task_queue::resume() {
    impl_ptr<impl>()->resume();
}

std::size_t task_queue::priority_count() const {
    return impl_ptr<impl>()->priority_count();
}

bool task_queue::is_suspended() const {
    return impl_ptr<impl>()->is_suspended();
}

bool task_queue::is_operating() const {
    return impl_ptr<impl>()->is_operating();
}
<|endoftext|>


<commit_before>/*
drive.cpp - Elegoo smartcar library implementation for driving functionality.
Created by the University of Minnesota Duluth Robotics Club
Fall, 2016
*/

#include "Arduino.h"
#include "drive.h"

Drive::Drive(const int& lPin1, const int& lPin2, const int& rPin1, const int& rPin2, const int& ENA_pin, const int& ENB_pin){

  rIn1 = rPin1;
  rIn2 = rPin2;
  lIn1 = lPin1;
  lIn2 = lPin2;
  ENA = ENA_pin;
  ENB = ENB_pin;

  checkPins();
}

int Drive::getRPin1() const{

  return rIn1;
}

int Drive::getRPin2() const{

  return rIn2;
}

int Drive::getLPin1() const{

  return lIn1;
}

int Drive::getLPin2() const{

  return lIn2;
}

int Drive::getENA() const{

  return ENA;
}

int Drive::getENB() const{

  return ENB;
}

void Drive::setPins(const int& lPin1, const int& lPin2, const int& rPin1, const int& rPin2, const int& ENA_pin, const int& ENB_pin){

  rIn1 = rPin1;
  rIn2 = rPin2;
  lIn1 = lPin1;
  lIn2 = lPin2;
  ENA = ENA_pin;
  ENB = ENB_pin;

  checkPins();
}

void Drive::fwdForTime(const int& time, const double& speed) const{

  write(speed, speed);
  delay(time);
  write(0, 0);
}

void Drive::bckForTime(const int& time, const double& speed) const{

  write(speed * -1, speed * -1);
  delay(time);
  write(0, 0);
}

void Drive::driveForTime(const int& time, const double& leftspeed, const double& rightspeed) const{

  write(leftspeed, rightspeed);
  delay(time);
  write(0, 0);
}

void Drive::move(const double& leftspeed, const double& rightspeed) const{

  write(leftspeed, rightspeed);
}

void Drive::checkPins() const{

  pinMode(rIn1, OUTPUT);
  pinMode(rIn2, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(lIn1, OUTPUT);
  pinMode(lIn2, OUTPUT);
  pinMode(ENA, OUTPUT);
}

void Drive::write(const double& leftspeed, const double& rightspeed) const{

  //Settings for left side.
  if (leftspeed > 0){ //Set left side to forward
    digitalWrite(lIn1, LOW);
    digitalWrite(lIn2, HIGH);
    if (leftspeed > 1)
      analogWrite(ENA, 1);
    else
      analogWrite(ENA, leftspeed * 255);
  }
  else if (leftspeed < 0){ //Set left side to reverse
    digitalWrite(lIn1, HIGH);
    digitalWrite(lIn2, LOW);
    if (leftspeed < -1)
      analogWrite(ENA, -1);
    else
      analogWrite(ENA, leftspeed * -255);
  }

  else{ //Set output to off. Don't care about ENA
    digitalWrite(lIn1, LOW);
    digitalWrite(lIn2, LOW);
  }

  //Settings for right side.
  if (rightspeed > 0){ //Set right side to forward
    digitalWrite(rIn1, LOW);
    digitalWrite(rIn2, HIGH);
    if (rightspeed > 1)
      analogWrite(ENB, 1);
    else
      analogWrite(ENB, rightspeed * 255);
  }
  else if (rightspeed < 0){ //Set right side to reverse
    digitalWrite(rIn1, HIGH);
    digitalWrite(rIn2, LOW);
    if (rightspeed < -1)
      analogWrite(ENB, -1);
    else
      analogWrite(ENB, rightspeed * -255);
  }

  else{ //Set output to off. Don't care about ENB
    digitalWrite(rIn1, LOW);
    digitalWrite(rIn2, LOW);
  }
}
<commit_msg>Made fix on Drive class<commit_after>/*
drive.cpp - Elegoo smartcar library implementation for driving functionality.
Created by the University of Minnesota Duluth Robotics Club
Fall, 2016
*/

#include "Arduino.h"
#include "drive.h"

Drive::Drive(const int& lPin1, const int& lPin2, const int& rPin1, const int& rPin2, const int& ENA_pin, const int& ENB_pin){

  rIn1 = rPin1;
  rIn2 = rPin2;
  lIn1 = lPin1;
  lIn2 = lPin2;
  ENA = ENA_pin;
  ENB = ENB_pin;

  checkPins();
}

int Drive::getRPin1() const{

  return rIn1;
}

int Drive::getRPin2() const{

  return rIn2;
}

int Drive::getLPin1() const{

  return lIn1;
}

int Drive::getLPin2() const{

  return lIn2;
}

int Drive::getENA() const{

  return ENA;
}

int Drive::getENB() const{

  return ENB;
}

void Drive::setPins(const int& lPin1, const int& lPin2, const int& rPin1, const int& rPin2, const int& ENA_pin, const int& ENB_pin){

  rIn1 = rPin1;
  rIn2 = rPin2;
  lIn1 = lPin1;
  lIn2 = lPin2;
  ENA = ENA_pin;
  ENB = ENB_pin;

  checkPins();
}

void Drive::fwdForTime(const int& time, const double& speed) const{

  write(speed, speed);
  delay(time);
  write(0, 0);
}

void Drive::bckForTime(const int& time, const double& speed) const{

  write(speed * -1, speed * -1);
  delay(time);
  write(0, 0);
}

void Drive::driveForTime(const int& time, const double& leftspeed, const double& rightspeed) const{

  write(leftspeed, rightspeed);
  delay(time);
  write(0, 0);
}

void Drive::move(const double& leftspeed, const double& rightspeed) const{

  write(leftspeed, rightspeed);
}

void Drive::checkPins() const{

  pinMode(rIn1, OUTPUT);
  pinMode(rIn2, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(lIn1, OUTPUT);
  pinMode(lIn2, OUTPUT);
  pinMode(ENA, OUTPUT);
}

void Drive::write(const double& leftspeed, const double& rightspeed) const{

  //Settings for left side.
  if (leftspeed > 0){ //Set left side to forward
    digitalWrite(lIn1, LOW);
    digitalWrite(lIn2, HIGH);
    if (leftspeed > 1)
      analogWrite(ENA, 255);
    else
      analogWrite(ENA, leftspeed * 255);
  }
  else if (leftspeed < 0){ //Set left side to reverse
    digitalWrite(lIn1, HIGH);
    digitalWrite(lIn2, LOW);
    if (leftspeed < -1)
      analogWrite(ENA, 255);
    else
      analogWrite(ENA, leftspeed * -255);
  }

  else{ //Set output to off. Don't care about ENA
    digitalWrite(lIn1, LOW);
    digitalWrite(lIn2, LOW);
  }

  //Settings for right side.
  if (rightspeed > 0){ //Set right side to forward
    digitalWrite(rIn1, LOW);
    digitalWrite(rIn2, HIGH);
    if (rightspeed > 1)
      analogWrite(ENB, 255);
    else
      analogWrite(ENB, rightspeed * 255);
  }
  else if (rightspeed < 0){ //Set right side to reverse
    digitalWrite(rIn1, HIGH);
    digitalWrite(rIn2, LOW);
    if (rightspeed < -1)
      analogWrite(ENB, 255);
    else
      analogWrite(ENB, rightspeed * -255);
  }

  else{ //Set output to off. Don't care about ENB
    digitalWrite(rIn1, LOW);
    digitalWrite(rIn2, LOW);
  }
}
<|endoftext|>


<commit_before>/****************** <VPR heading BEGIN do not edit this line> *****************
 *
 * VR Juggler Portable Runtime
 *
 * Original Authors:
 *   Allen Bierbaum, Patrick Hartling, Kevin Meinert, Carolina Cruz-Neira
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 *
 ****************** <VPR heading END do not edit this line> ******************/

/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998, 1999, 2000, 2001 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

#include <vpr/vprConfig.h>

#include <boost/utility.hpp>
#include <vpr/Util/Interval.h>
#include <vpr/Util/Debug.h>
#include <vpr/Thread/Thread.h>

#include <vpr/md/SIM/Network/Message.h>
#include <vpr/md/SIM/Network/MessagePtr.h>
#include <vpr/md/SIM/IO/Socket/SocketImplSIM.h>
#include <vpr/md/SIM/Controller.h>

namespace vpr
{

namespace sim
{

Controller* Controller::mPrimordialInstance = NULL;
vpr::TSObjectProxy<Controller::ControllerTS> Controller::mInstance;

// ============================================================================
// Public methods.
// ============================================================================

Controller::Controller ()
   : mSleepTime(0)
{
   /* Do nothing. */ ;
}

vpr::ReturnStatus Controller::constructNetwork (const std::string& graph_file)
{
   vpr::ReturnStatus status;

   if ( mGraph.isValid() )
   {
      mGraph.clear();
   }

   status = mGraph.construct(graph_file);

   if ( status.success() )
   {
      mSocketManager.setActive();
   }

   return status;
}

void Controller::addEvent (const vpr::Interval& event_time,
                           const NetworkGraph::net_edge_t edge,
                           const NetworkLine::LineDirection dir)
{
   vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
      << "Controller::addEvent(): Adding event scheduled for time "
      << event_time.getBaseVal() << " on edge " << edge << "\n"
      << vprDEBUG_FLUSH;
   mEvents.insert(std::pair<vpr::Interval, EventData>(event_time, EventData(edge, dir)));
}

void Controller::processNextEvent ()
{
   event_map_t::iterator cur_event = mEvents.begin();

   if ( cur_event != mEvents.end() )
   {
      vpr::Interval event_time            = (*cur_event).first;
      NetworkGraph::net_edge_t event_edge = (*cur_event).second.edge;
      NetworkLine::LineDirection dir      = (*cur_event).second.direction;
      vpr::sim::NetworkLine line          = mGraph.getLineProperty(event_edge);
      vpr::sim::MessagePtr msg;
      vpr::ReturnStatus status;

      vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
         << "Controller::processNextEvent() [time = "
         << mClock.getCurrentTime().getBaseVal()
         << "]: Processing event scheduled to occur at time "
         << event_time.getBaseVal() << "\n" << vprDEBUG_FLUSH;

      // ----------------------------------------------------------------------
      // Process event in the line's transmission queue.
      // ----------------------------------------------------------------------

      status = line.getArrivedMessage(event_time, msg, dir);
      vprASSERT(status.success() && "No arrived message at this time");

      vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
         << "Controller::processNextEvent(): Event is an arrived message on "
         << "forward queue of line " << line.getNetworkAddressString()
         << "\n" << vprDEBUG_FLUSH;
      mClock.setCurrentTime(event_time);
      moveMessage(msg, event_time);

      mEvents.erase(cur_event);

      if ( mSleepTime != 0 )
      {
         vpr::Thread::usleep(mSleepTime);
      }
   }
}

void Controller::processEvents (const vpr::Interval& time_step)
{
   vpr::Interval event_time = mClock.getCurrentTime() + time_step;
   event_map_t::iterator next_event;

   mClock.setCurrentTime(event_time);

   // The current time based on the time step is the same as or greater than
   // the time of the next event in the queue.  That means that that event is
   // eligible for processing.
   while ( (next_event = mEvents.begin()) != mEvents.end() &&
           (*next_event).first <= event_time )
   {
      processNextEvent();
   }
}

// ============================================================================
// Private methods.
// ============================================================================

void Controller::moveMessage (vpr::sim::MessagePtr msg,
                              const vpr::Interval& cur_time)
{
   NetworkGraph::net_vertex_t next_hop = msg->getNextHop();

   bool end_of_path;
   msg->incNextHop(end_of_path);

   // Pass the message on to the next line.
   if ( ! end_of_path )
   {
      NetworkGraph::net_vertex_t next_next_hop = msg->getNextHop();
      NetworkGraph::net_edge_t next_line;
      bool got_next_line;
      vpr::sim::NetworkLine next_line_prop;
      NetworkLine::LineDirection dir;

      boost::tie(next_line, got_next_line) = mGraph.getEdge(next_hop,
                                                            next_next_hop);
      vprASSERT(got_next_line && "Edge between nodes not found!");

      vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
         << "Controller::moveMessage(): Passing message on to next hop -- "
         << next_line << "\n" << vprDEBUG_FLUSH;

      dir = mGraph.isSource(next_hop, next_line) ? NetworkLine::FORWARD
                                                 : NetworkLine::REVERSE;

      next_line_prop = mGraph.getLineProperty(next_line);
      next_line_prop.calculateMessageEventTimes(msg, cur_time, dir);

      vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
         << "New message times: "
         << "starts = " << msg->whenStartOnWire().getBaseVal() << ", "
         << "transmits = " << msg->whenFullyOnWire().getBaseVal() << ", "
         << "arrives = " << msg->whenArrivesFully().getBaseVal()
         << std::endl << vprDEBUG_FLUSH;

      next_line_prop.addMessage(msg, dir);
      mGraph.setLineProperty(next_line, next_line_prop);
      addEvent(msg->whenArrivesFully(), next_line, dir);
   }
   // End of the path--we have reached our destination.
   else
   {
      msg->getDestinationSocket()->addArrivedMessage(msg);

      // The above should be the last use of the memory held by msg, so the
      // should get deleted when the value of msg changes.
   }
}

} // End of sim namespace

} // End of vpr namespace
<commit_msg>In processNextEvent(), when we remove the message at the head of the head of the current line's queue, we have to update that line's property.  What a pain.  This was causing a nasty little bug related to changes made last Friday.<commit_after>/****************** <VPR heading BEGIN do not edit this line> *****************
 *
 * VR Juggler Portable Runtime
 *
 * Original Authors:
 *   Allen Bierbaum, Patrick Hartling, Kevin Meinert, Carolina Cruz-Neira
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 *
 ****************** <VPR heading END do not edit this line> ******************/

/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998, 1999, 2000, 2001 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

#include <vpr/vprConfig.h>

#include <boost/utility.hpp>
#include <vpr/Util/Interval.h>
#include <vpr/Util/Debug.h>
#include <vpr/Thread/Thread.h>

#include <vpr/md/SIM/Network/Message.h>
#include <vpr/md/SIM/Network/MessagePtr.h>
#include <vpr/md/SIM/IO/Socket/SocketImplSIM.h>
#include <vpr/md/SIM/Controller.h>

namespace vpr
{

namespace sim
{

Controller* Controller::mPrimordialInstance = NULL;
vpr::TSObjectProxy<Controller::ControllerTS> Controller::mInstance;

// ============================================================================
// Public methods.
// ============================================================================

Controller::Controller ()
   : mSleepTime(0)
{
   /* Do nothing. */ ;
}

vpr::ReturnStatus Controller::constructNetwork (const std::string& graph_file)
{
   vpr::ReturnStatus status;

   if ( mGraph.isValid() )
   {
      mGraph.clear();
   }

   status = mGraph.construct(graph_file);

   if ( status.success() )
   {
      mSocketManager.setActive();
   }

   return status;
}

void Controller::addEvent (const vpr::Interval& event_time,
                           const NetworkGraph::net_edge_t edge,
                           const NetworkLine::LineDirection dir)
{
   vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
      << "Controller::addEvent(): Adding event scheduled for time "
      << event_time.getBaseVal() << " on edge " << edge << "\n"
      << vprDEBUG_FLUSH;
   mEvents.insert(std::pair<vpr::Interval, EventData>(event_time, EventData(edge, dir)));
}

void Controller::processNextEvent ()
{
   event_map_t::iterator cur_event = mEvents.begin();

   if ( cur_event != mEvents.end() )
   {
      vpr::Interval event_time            = (*cur_event).first;
      NetworkGraph::net_edge_t event_edge = (*cur_event).second.edge;
      NetworkLine::LineDirection dir      = (*cur_event).second.direction;
      vpr::sim::NetworkLine line          = mGraph.getLineProperty(event_edge);
      vpr::sim::MessagePtr msg;
      vpr::ReturnStatus status;

      vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
         << "Controller::processNextEvent() [time = "
         << mClock.getCurrentTime().getBaseVal()
         << "]: Processing event scheduled to occur at time "
         << event_time.getBaseVal() << "\n" << vprDEBUG_FLUSH;

      // ----------------------------------------------------------------------
      // Process event in the line's transmission queue.
      // ----------------------------------------------------------------------

      status = line.getArrivedMessage(event_time, msg, dir);
      mGraph.setLineProperty(event_edge, line);
      vprASSERT(status.success() && "No arrived message at this time");

      vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
         << "Controller::processNextEvent(): Event is an arrived message on "
         << "forward queue of line " << line.getNetworkAddressString()
         << "\n" << vprDEBUG_FLUSH;
      mClock.setCurrentTime(event_time);
      moveMessage(msg, event_time);

      mEvents.erase(cur_event);

      if ( mSleepTime != 0 )
      {
         vpr::Thread::usleep(mSleepTime);
      }
   }
}

void Controller::processEvents (const vpr::Interval& time_step)
{
   vpr::Interval event_time = mClock.getCurrentTime() + time_step;
   event_map_t::iterator next_event;

   mClock.setCurrentTime(event_time);

   // The current time based on the time step is the same as or greater than
   // the time of the next event in the queue.  That means that that event is
   // eligible for processing.
   while ( (next_event = mEvents.begin()) != mEvents.end() &&
           (*next_event).first <= event_time )
   {
      processNextEvent();
   }
}

// ============================================================================
// Private methods.
// ============================================================================

void Controller::moveMessage (vpr::sim::MessagePtr msg,
                              const vpr::Interval& cur_time)
{
   NetworkGraph::net_vertex_t next_hop = msg->getNextHop();

   bool end_of_path;
   msg->incNextHop(end_of_path);

   // Pass the message on to the next line.
   if ( ! end_of_path )
   {
      NetworkGraph::net_vertex_t next_next_hop = msg->getNextHop();
      NetworkGraph::net_edge_t next_line;
      bool got_next_line;
      vpr::sim::NetworkLine next_line_prop;
      NetworkLine::LineDirection dir;

      boost::tie(next_line, got_next_line) = mGraph.getEdge(next_hop,
                                                            next_next_hop);
      vprASSERT(got_next_line && "Edge between nodes not found!");

      vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
         << "Controller::moveMessage(): Passing message on to next hop -- "
         << next_line << "\n" << vprDEBUG_FLUSH;

      dir = mGraph.isSource(next_hop, next_line) ? NetworkLine::FORWARD
                                                 : NetworkLine::REVERSE;

      next_line_prop = mGraph.getLineProperty(next_line);
      next_line_prop.calculateMessageEventTimes(msg, cur_time, dir);

      vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
         << "Controller::moveMessage(): New message times: "
         << "starts = " << msg->whenStartOnWire().getBaseVal() << ", "
         << "transmits = " << msg->whenFullyOnWire().getBaseVal() << ", "
         << "arrives = " << msg->whenArrivesFully().getBaseVal()
         << std::endl << vprDEBUG_FLUSH;

      next_line_prop.addMessage(msg, dir);
      mGraph.setLineProperty(next_line, next_line_prop);
      addEvent(msg->whenArrivesFully(), next_line, dir);
   }
   // End of the path--we have reached our destination.
   else
   {
      vprDEBUG(vprDBG_ALL, vprDBG_STATE_LVL)
         << "Controller::moveMessage() [time = "
         << mClock.getCurrentTime().getBaseVal()
         << "]: Delivering message to destination "
         << msg->getDestinationSocket()->getLocalAddr() << std::endl
         << vprDEBUG_FLUSH;

      msg->getDestinationSocket()->addArrivedMessage(msg);

      // The above should be the last use of the memory held by msg, so the
      // should get deleted when the value of msg changes.
   }
}

} // End of sim namespace

} // End of vpr namespace
<|endoftext|>