<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "runenvironment.h"

#include <api/projectdata.h>
#include <buildgraph/productinstaller.h>
#include <language/language.h>
#include <language/propertymapinternal.h>
#include <language/scriptengine.h>
#include <logging/logger.h>
#include <logging/translator.h>
#include <tools/error.h>
#include <tools/fileinfo.h>
#include <tools/hostosinfo.h>
#include <tools/installoptions.h>
#include <tools/preferences.h>
#include <tools/propertyfinder.h>
#include <tools/qbsassert.h>
#include <tools/shellutils.h>

#include <QDir>
#include <QProcess>
#include <QProcessEnvironment>
#include <QScopedPointer>
#include <QTemporaryFile>
#include <QVariantMap>

#include <stdlib.h>

namespace qbs {
using namespace Internal;

class RunEnvironment::RunEnvironmentPrivate
{
public:
    RunEnvironmentPrivate(const ResolvedProductPtr &product, const InstallOptions &installOptions,
            const QProcessEnvironment &environment, Settings *settings, const Logger &logger)
        : engine(logger)
        , resolvedProduct(product)
        , installOptions(installOptions)
        , environment(environment)
        , settings(settings)
        , logger(logger)
    {
    }

    ScriptEngine engine;
    const ResolvedProductPtr resolvedProduct;
    InstallOptions installOptions;
    const QProcessEnvironment environment;
    Settings * const settings;
    Logger logger;
};

RunEnvironment::RunEnvironment(const ResolvedProductPtr &product,
        const InstallOptions &installOptions,
        const QProcessEnvironment &environment, Settings *settings, const Logger &logger)
    : d(new RunEnvironmentPrivate(product, installOptions, environment, settings, logger))
{
}

RunEnvironment::~RunEnvironment()
{
    delete d;
}

int RunEnvironment::runShell(ErrorInfo *error)
{
    try {
        return doRunShell();
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return -1;
    }
}

int RunEnvironment::runTarget(const QString &targetBin, const QStringList &arguments,
                              ErrorInfo *error)
{
    try {
        return doRunTarget(targetBin, arguments);
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return -1;
    }
}

const QProcessEnvironment RunEnvironment::runEnvironment(ErrorInfo *error) const
{
    try {
        return getRunEnvironment();
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return QProcessEnvironment();
    }
}

const QProcessEnvironment RunEnvironment::buildEnvironment(ErrorInfo *error) const
{
    try {
        return getBuildEnvironment();
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return QProcessEnvironment();
    }
}

int RunEnvironment::doRunShell()
{
    d->resolvedProduct->setupBuildEnvironment(&d->engine, d->environment);

    const QString productId = d->resolvedProduct->name;
    d->logger.qbsInfo() << Tr::tr("Starting shell for target '%1'.").arg(productId);
    const QProcessEnvironment environment = d->resolvedProduct->buildEnvironment;
#if defined(Q_OS_LINUX)
    clearenv();
#endif
    foreach (const QString &key, environment.keys())
        qputenv(key.toLocal8Bit().constData(), environment.value(key).toLocal8Bit());
    QString command;
    QScopedPointer<QTemporaryFile> envFile;
    if (HostOsInfo::isWindowsHost()) {
        command = environment.value(QLatin1String("COMSPEC"));
        if (command.isEmpty())
            command = QLatin1String("cmd");
        const QString prompt = environment.value(QLatin1String("PROMPT"));
        command += QLatin1String(" /k prompt [qbs] ") + prompt;
    } else {
        const QVariantMap qbsProps = d->resolvedProduct->topLevelProject()->buildConfiguration()
                .value(QLatin1String("qbs")).toMap();
        const QString profileName = qbsProps.value(QLatin1String("profile")).toString();
        command = Preferences(d->settings, profileName).shell();
        if (command.isEmpty())
            command = environment.value(QLatin1String("SHELL"), QLatin1String("/bin/sh"));

        // Yes, we have to use this prcoedure. PS1 is not inherited from the environment.
        const QString prompt = QLatin1String("qbs ") + productId + QLatin1String(" $ ");
        envFile.reset(new QTemporaryFile);
        if (envFile->open()) {
            if (command.endsWith(QLatin1String("bash")))
                command += QLatin1String(" --posix"); // Teach bash some manners.
            const QString promptLine = QLatin1String("PS1='") + prompt + QLatin1String("'\n");
            envFile->write(promptLine.toLocal8Bit());
            envFile->close();
            qputenv("ENV", envFile->fileName().toLocal8Bit());
        } else {
            d->logger.qbsWarning() << Tr::tr("Setting custom shell prompt failed.");
        }
    }

    // We cannot use QProcess, since it does not do stdin forwarding.
    return system(command.toLocal8Bit().constData());
}

static QString findExecutable(const QStringList &fileNames)
{
    const QStringList path = QString::fromLocal8Bit(qgetenv("PATH"))
            .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts);

    foreach (const QString &fileName, fileNames) {
        const QString exeFileName = HostOsInfo::appendExecutableSuffix(fileName);
        foreach (const QString &ppath, path) {
            const QString fullPath = ppath + QLatin1Char('/') + exeFileName;
            QFileInfo fi(fullPath);
            if (fi.exists() && fi.isFile() && fi.isExecutable())
                return QDir::cleanPath(fullPath);
        }
    }
    return QString();
}

int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arguments)
{
    const QStringList targetOS = PropertyFinder().propertyValue(
                d->resolvedProduct->moduleProperties->value(),
                QLatin1String("qbs"),
                QLatin1String("targetOS")).toStringList();

    const QStringList toolchain = PropertyFinder().propertyValue(
                d->resolvedProduct->moduleProperties->value(),
                QLatin1String("qbs"),
                QLatin1String("toolchain")).toStringList();

    QString targetExecutable = targetBin;
    QStringList targetArguments = arguments;
    const QString completeSuffix = QFileInfo(targetBin).completeSuffix();

    if (targetOS.contains(QLatin1String("ios"))) {
        QString bundlePath = d->resolvedProduct->buildDirectory();
        const bool install = PropertyFinder().propertyValue(
                    d->resolvedProduct->moduleProperties->value(),
                    QLatin1String("qbs"),
                    QLatin1String("install")).toBool();
        if (install) {
            bundlePath = d->installOptions.installRoot();
            const QString installDir = PropertyFinder().propertyValue(
                        d->resolvedProduct->moduleProperties->value(),
                        QLatin1String("qbs"),
                        QLatin1String("installDir")).toString();
            bundlePath += QLatin1Char('/') + installDir;
        }

        const QString bundleName = PropertyFinder().propertyValue(
                    d->resolvedProduct->moduleProperties->value(),
                    QLatin1String("bundle"),
                    QLatin1String("bundleName")).toString();
        bundlePath += QLatin1Char('/') + bundleName;

        QBS_CHECK(targetExecutable.startsWith(bundlePath));

        if (QFileInfo(targetExecutable = findExecutable(QStringList()
                    << QStringLiteral("iostool"))).isExecutable()) {
            targetArguments = QStringList()
                    << QStringLiteral("-run")
                    << QStringLiteral("-bundle")
                    << QDir::cleanPath(bundlePath);
            if (!arguments.isEmpty())
                targetArguments << QStringLiteral("-extra-args") << arguments;
        } else if (QFileInfo(targetExecutable = findExecutable(QStringList()
                    << QStringLiteral("ios-deploy"))).isExecutable()) {
            targetArguments = QStringList()
                    << QStringLiteral("--noninteractive")
                    << QStringLiteral("--bundle")
                    << QDir::cleanPath(bundlePath);
            if (!arguments.isEmpty())
                targetArguments << QStringLiteral("--args") << arguments;
        } else {
            d->logger.qbsLog(LoggerError)
                    << Tr::tr("No suitable iOS deployment tools were found in the environment. "
                              "Consider installing ios-deploy.");
            return EXIT_FAILURE;
        }
    } else if (targetOS.contains(QLatin1String("windows"))) {
        if (completeSuffix == QLatin1String("msi")) {
            targetExecutable = QLatin1String("msiexec");
            targetArguments.prepend(QDir::toNativeSeparators(targetBin));
            targetArguments.prepend(QLatin1String("/package"));
        }

        // Run Windows executables through Wine when not on Windows
        if (!HostOsInfo::isWindowsHost()) {
            targetArguments.prepend(targetExecutable);
            targetExecutable = QLatin1String("wine");
        }
    }

    if (toolchain.contains(QLatin1String("mono"))) {
        targetArguments.prepend(targetExecutable);
        targetExecutable = QLatin1String("mono");
    }

    if (completeSuffix == QLatin1String("js")) {
        // The Node.js binary is called nodejs on Debian/Ubuntu-family operating systems due to a
        // conflict with another package containing a binary named node
        targetExecutable = findExecutable(QStringList()
                                          << QLatin1String("nodejs")
                                          << QLatin1String("node"));
        targetArguments.prepend(targetBin);
    }

    // Only check if the target is executable if we're not running it through another
    // known application such as msiexec or wine, as we can't check in this case anyways
    QFileInfo fi(targetExecutable);
    if (targetBin == targetExecutable && (!fi.isFile() || !fi.isExecutable())) {
        d->logger.qbsLog(LoggerError) << Tr::tr("File '%1' is not an executable.")
                                .arg(QDir::toNativeSeparators(targetExecutable));
        return EXIT_FAILURE;
    }

    QProcessEnvironment env = d->environment;
    env.insert(QLatin1String("QBS_RUN_FILE_PATH"), targetBin);
    d->resolvedProduct->setupRunEnvironment(&d->engine, env);

    d->logger.qbsInfo() << Tr::tr("Starting target '%1'.").arg(QDir::toNativeSeparators(targetBin));
    QProcess process;
    process.setProcessEnvironment(d->resolvedProduct->runEnvironment);
    process.setProcessChannelMode(QProcess::ForwardedChannels);
    process.start(targetExecutable, targetArguments);
    if (!process.waitForFinished(-1)) {
        if (process.error() == QProcess::FailedToStart) {
            QString errorPrefixString;
#ifdef Q_OS_UNIX
            if (QFileInfo(targetExecutable).isExecutable()) {
                const QString interpreter(shellInterpreter(targetExecutable));
                if (!interpreter.isEmpty()) {
                    errorPrefixString = Tr::tr("%1: bad interpreter: ").arg(interpreter);
                }
            }
#endif
            throw ErrorInfo(Tr::tr("The process '%1' could not be started: %2")
                            .arg(targetExecutable)
                            .arg(errorPrefixString + process.errorString()));
        } else {
            d->logger.qbsWarning()
                    << "QProcess error: " << process.errorString();
        }

        return EXIT_FAILURE;
    }
    return process.exitCode();
}

const QProcessEnvironment RunEnvironment::getRunEnvironment() const
{
    d->resolvedProduct->setupRunEnvironment(&d->engine, d->environment);
    return d->resolvedProduct->runEnvironment;
}

const QProcessEnvironment RunEnvironment::getBuildEnvironment() const
{
    d->resolvedProduct->setupBuildEnvironment(&d->engine, d->environment);
    return d->resolvedProduct->buildEnvironment;
}

} // namespace qbs
<commit_msg>Ignore WiFi devices during iOS deployment.<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "runenvironment.h"

#include <api/projectdata.h>
#include <buildgraph/productinstaller.h>
#include <language/language.h>
#include <language/propertymapinternal.h>
#include <language/scriptengine.h>
#include <logging/logger.h>
#include <logging/translator.h>
#include <tools/error.h>
#include <tools/fileinfo.h>
#include <tools/hostosinfo.h>
#include <tools/installoptions.h>
#include <tools/preferences.h>
#include <tools/propertyfinder.h>
#include <tools/qbsassert.h>
#include <tools/shellutils.h>

#include <QDir>
#include <QProcess>
#include <QProcessEnvironment>
#include <QScopedPointer>
#include <QTemporaryFile>
#include <QVariantMap>

#include <stdlib.h>

namespace qbs {
using namespace Internal;

class RunEnvironment::RunEnvironmentPrivate
{
public:
    RunEnvironmentPrivate(const ResolvedProductPtr &product, const InstallOptions &installOptions,
            const QProcessEnvironment &environment, Settings *settings, const Logger &logger)
        : engine(logger)
        , resolvedProduct(product)
        , installOptions(installOptions)
        , environment(environment)
        , settings(settings)
        , logger(logger)
    {
    }

    ScriptEngine engine;
    const ResolvedProductPtr resolvedProduct;
    InstallOptions installOptions;
    const QProcessEnvironment environment;
    Settings * const settings;
    Logger logger;
};

RunEnvironment::RunEnvironment(const ResolvedProductPtr &product,
        const InstallOptions &installOptions,
        const QProcessEnvironment &environment, Settings *settings, const Logger &logger)
    : d(new RunEnvironmentPrivate(product, installOptions, environment, settings, logger))
{
}

RunEnvironment::~RunEnvironment()
{
    delete d;
}

int RunEnvironment::runShell(ErrorInfo *error)
{
    try {
        return doRunShell();
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return -1;
    }
}

int RunEnvironment::runTarget(const QString &targetBin, const QStringList &arguments,
                              ErrorInfo *error)
{
    try {
        return doRunTarget(targetBin, arguments);
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return -1;
    }
}

const QProcessEnvironment RunEnvironment::runEnvironment(ErrorInfo *error) const
{
    try {
        return getRunEnvironment();
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return QProcessEnvironment();
    }
}

const QProcessEnvironment RunEnvironment::buildEnvironment(ErrorInfo *error) const
{
    try {
        return getBuildEnvironment();
    } catch (const ErrorInfo &e) {
        if (error)
            *error = e;
        return QProcessEnvironment();
    }
}

int RunEnvironment::doRunShell()
{
    d->resolvedProduct->setupBuildEnvironment(&d->engine, d->environment);

    const QString productId = d->resolvedProduct->name;
    d->logger.qbsInfo() << Tr::tr("Starting shell for target '%1'.").arg(productId);
    const QProcessEnvironment environment = d->resolvedProduct->buildEnvironment;
#if defined(Q_OS_LINUX)
    clearenv();
#endif
    foreach (const QString &key, environment.keys())
        qputenv(key.toLocal8Bit().constData(), environment.value(key).toLocal8Bit());
    QString command;
    QScopedPointer<QTemporaryFile> envFile;
    if (HostOsInfo::isWindowsHost()) {
        command = environment.value(QLatin1String("COMSPEC"));
        if (command.isEmpty())
            command = QLatin1String("cmd");
        const QString prompt = environment.value(QLatin1String("PROMPT"));
        command += QLatin1String(" /k prompt [qbs] ") + prompt;
    } else {
        const QVariantMap qbsProps = d->resolvedProduct->topLevelProject()->buildConfiguration()
                .value(QLatin1String("qbs")).toMap();
        const QString profileName = qbsProps.value(QLatin1String("profile")).toString();
        command = Preferences(d->settings, profileName).shell();
        if (command.isEmpty())
            command = environment.value(QLatin1String("SHELL"), QLatin1String("/bin/sh"));

        // Yes, we have to use this prcoedure. PS1 is not inherited from the environment.
        const QString prompt = QLatin1String("qbs ") + productId + QLatin1String(" $ ");
        envFile.reset(new QTemporaryFile);
        if (envFile->open()) {
            if (command.endsWith(QLatin1String("bash")))
                command += QLatin1String(" --posix"); // Teach bash some manners.
            const QString promptLine = QLatin1String("PS1='") + prompt + QLatin1String("'\n");
            envFile->write(promptLine.toLocal8Bit());
            envFile->close();
            qputenv("ENV", envFile->fileName().toLocal8Bit());
        } else {
            d->logger.qbsWarning() << Tr::tr("Setting custom shell prompt failed.");
        }
    }

    // We cannot use QProcess, since it does not do stdin forwarding.
    return system(command.toLocal8Bit().constData());
}

static QString findExecutable(const QStringList &fileNames)
{
    const QStringList path = QString::fromLocal8Bit(qgetenv("PATH"))
            .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts);

    foreach (const QString &fileName, fileNames) {
        const QString exeFileName = HostOsInfo::appendExecutableSuffix(fileName);
        foreach (const QString &ppath, path) {
            const QString fullPath = ppath + QLatin1Char('/') + exeFileName;
            QFileInfo fi(fullPath);
            if (fi.exists() && fi.isFile() && fi.isExecutable())
                return QDir::cleanPath(fullPath);
        }
    }
    return QString();
}

int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arguments)
{
    const QStringList targetOS = PropertyFinder().propertyValue(
                d->resolvedProduct->moduleProperties->value(),
                QLatin1String("qbs"),
                QLatin1String("targetOS")).toStringList();

    const QStringList toolchain = PropertyFinder().propertyValue(
                d->resolvedProduct->moduleProperties->value(),
                QLatin1String("qbs"),
                QLatin1String("toolchain")).toStringList();

    QString targetExecutable = targetBin;
    QStringList targetArguments = arguments;
    const QString completeSuffix = QFileInfo(targetBin).completeSuffix();

    if (targetOS.contains(QLatin1String("ios"))) {
        QString bundlePath = d->resolvedProduct->buildDirectory();
        const bool install = PropertyFinder().propertyValue(
                    d->resolvedProduct->moduleProperties->value(),
                    QLatin1String("qbs"),
                    QLatin1String("install")).toBool();
        if (install) {
            bundlePath = d->installOptions.installRoot();
            const QString installDir = PropertyFinder().propertyValue(
                        d->resolvedProduct->moduleProperties->value(),
                        QLatin1String("qbs"),
                        QLatin1String("installDir")).toString();
            bundlePath += QLatin1Char('/') + installDir;
        }

        const QString bundleName = PropertyFinder().propertyValue(
                    d->resolvedProduct->moduleProperties->value(),
                    QLatin1String("bundle"),
                    QLatin1String("bundleName")).toString();
        bundlePath += QLatin1Char('/') + bundleName;

        QBS_CHECK(targetExecutable.startsWith(bundlePath));

        if (QFileInfo(targetExecutable = findExecutable(QStringList()
                    << QStringLiteral("iostool"))).isExecutable()) {
            targetArguments = QStringList()
                    << QStringLiteral("-run")
                    << QStringLiteral("-bundle")
                    << QDir::cleanPath(bundlePath);
            if (!arguments.isEmpty())
                targetArguments << QStringLiteral("-extra-args") << arguments;
        } else if (QFileInfo(targetExecutable = findExecutable(QStringList()
                    << QStringLiteral("ios-deploy"))).isExecutable()) {
            targetArguments = QStringList()
                    << QStringLiteral("--no-wifi")
                    << QStringLiteral("--noninteractive")
                    << QStringLiteral("--bundle")
                    << QDir::cleanPath(bundlePath);
            if (!arguments.isEmpty())
                targetArguments << QStringLiteral("--args") << arguments;
        } else {
            d->logger.qbsLog(LoggerError)
                    << Tr::tr("No suitable iOS deployment tools were found in the environment. "
                              "Consider installing ios-deploy.");
            return EXIT_FAILURE;
        }
    } else if (targetOS.contains(QLatin1String("windows"))) {
        if (completeSuffix == QLatin1String("msi")) {
            targetExecutable = QLatin1String("msiexec");
            targetArguments.prepend(QDir::toNativeSeparators(targetBin));
            targetArguments.prepend(QLatin1String("/package"));
        }

        // Run Windows executables through Wine when not on Windows
        if (!HostOsInfo::isWindowsHost()) {
            targetArguments.prepend(targetExecutable);
            targetExecutable = QLatin1String("wine");
        }
    }

    if (toolchain.contains(QLatin1String("mono"))) {
        targetArguments.prepend(targetExecutable);
        targetExecutable = QLatin1String("mono");
    }

    if (completeSuffix == QLatin1String("js")) {
        // The Node.js binary is called nodejs on Debian/Ubuntu-family operating systems due to a
        // conflict with another package containing a binary named node
        targetExecutable = findExecutable(QStringList()
                                          << QLatin1String("nodejs")
                                          << QLatin1String("node"));
        targetArguments.prepend(targetBin);
    }

    // Only check if the target is executable if we're not running it through another
    // known application such as msiexec or wine, as we can't check in this case anyways
    QFileInfo fi(targetExecutable);
    if (targetBin == targetExecutable && (!fi.isFile() || !fi.isExecutable())) {
        d->logger.qbsLog(LoggerError) << Tr::tr("File '%1' is not an executable.")
                                .arg(QDir::toNativeSeparators(targetExecutable));
        return EXIT_FAILURE;
    }

    QProcessEnvironment env = d->environment;
    env.insert(QLatin1String("QBS_RUN_FILE_PATH"), targetBin);
    d->resolvedProduct->setupRunEnvironment(&d->engine, env);

    d->logger.qbsInfo() << Tr::tr("Starting target '%1'.").arg(QDir::toNativeSeparators(targetBin));
    QProcess process;
    process.setProcessEnvironment(d->resolvedProduct->runEnvironment);
    process.setProcessChannelMode(QProcess::ForwardedChannels);
    process.start(targetExecutable, targetArguments);
    if (!process.waitForFinished(-1)) {
        if (process.error() == QProcess::FailedToStart) {
            QString errorPrefixString;
#ifdef Q_OS_UNIX
            if (QFileInfo(targetExecutable).isExecutable()) {
                const QString interpreter(shellInterpreter(targetExecutable));
                if (!interpreter.isEmpty()) {
                    errorPrefixString = Tr::tr("%1: bad interpreter: ").arg(interpreter);
                }
            }
#endif
            throw ErrorInfo(Tr::tr("The process '%1' could not be started: %2")
                            .arg(targetExecutable)
                            .arg(errorPrefixString + process.errorString()));
        } else {
            d->logger.qbsWarning()
                    << "QProcess error: " << process.errorString();
        }

        return EXIT_FAILURE;
    }
    return process.exitCode();
}

const QProcessEnvironment RunEnvironment::getRunEnvironment() const
{
    d->resolvedProduct->setupRunEnvironment(&d->engine, d->environment);
    return d->resolvedProduct->runEnvironment;
}

const QProcessEnvironment RunEnvironment::getBuildEnvironment() const
{
    d->resolvedProduct->setupBuildEnvironment(&d->engine, d->environment);
    return d->resolvedProduct->buildEnvironment;
}

} // namespace qbs
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmljspropertyreader.h"
#include "qmljsdocument.h"
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsutils.h>

#include <QLinearGradient>

namespace QmlJS {

using namespace AST;

namespace {

static inline QString deEscape(const QString &value)
{
    QString result = value;

    result.replace(QLatin1String("\\\\"), QLatin1String("\\"));
    result.replace(QLatin1String("\\\""), QLatin1String("\""));
    result.replace(QLatin1String("\\\t"), QLatin1String("\t"));
    result.replace(QLatin1String("\\\r"), QLatin1String("\r"));
    result.replace(QLatin1String("\\\n"), QLatin1String("\n"));

    return result;
}

static inline QString stripQuotes(const QString &str)
{
    if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
            || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
        return str.mid(1, str.length() - 2);

    return str;
}

static bool isLiteralValue(ExpressionNode *expr)
{
    if (cast<NumericLiteral*>(expr))
        return true;
    else if (cast<StringLiteral*>(expr))
        return true;
    else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr))
        return isLiteralValue(plusExpr->expression);
    else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr))
        return isLiteralValue(minusExpr->expression);
    else if (cast<TrueLiteral*>(expr))
        return true;
    else if (cast<FalseLiteral*>(expr))
        return true;
    else
        return false;
}

static inline bool isLiteralValue(UiScriptBinding *script)
{
    if (!script || !script->statement)
        return false;

    ExpressionStatement *exprStmt = cast<ExpressionStatement *>(script->statement);
    if (exprStmt)
        return isLiteralValue(exprStmt->expression);
    else
        return false;
}

static inline QString textAt(const Document::Ptr doc,
                                  const SourceLocation &from,
                                  const SourceLocation &to)
{
    return doc->source().mid(from.offset, to.end() - from.begin());
}

static inline int propertyType(const QString &typeName)
{
    if (typeName == QLatin1String("bool"))
        return QMetaType::type("bool");
    else if (typeName == QLatin1String("color"))
        return QMetaType::type("QColor");
    else if (typeName == QLatin1String("date"))
        return QMetaType::type("QDate");
    else if (typeName == QLatin1String("int"))
        return QMetaType::type("int");
    else if (typeName == QLatin1String("real"))
        return QMetaType::type("double");
    else if (typeName == QLatin1String("double"))
        return QMetaType::type("double");
    else if (typeName == QLatin1String("string"))
        return QMetaType::type("QString");
    else if (typeName == QLatin1String("url"))
        return QMetaType::type("QUrl");
    else if (typeName == QLatin1String("variant"))
        return QMetaType::type("QVariant");
    else
        return -1;
}

static bool isEnum(AST::Statement *ast);

bool isEnum(AST::ExpressionNode *ast)
{
    if (!ast)
        return false;

    if (FieldMemberExpression *memberExpr = cast<AST::FieldMemberExpression*>(ast))
        return isEnum(memberExpr->base);
    else if (cast<IdentifierExpression*>(ast))
        return true;
    else
        return false;
}

static bool isEnum(AST::Statement *ast)
{
    if (!ast)
        return false;

    if (ExpressionStatement *exprStmt = cast<ExpressionStatement*>(ast))
        return isEnum(exprStmt->expression);
    return false;
}

static QString cleanupSemicolon(const QString &str)
{
    QString out = str;
    while (out.endsWith(QLatin1Char(';')))
        out.chop(1);
    return out;
}

} // anonymous namespace

PropertyReader::PropertyReader(Document::Ptr doc, AST::UiObjectInitializer *ast)
{
    m_ast = ast;
    m_doc = doc;

    if (!m_doc)
        return;

    for (UiObjectMemberList *members = ast->members; members; members = members->next) {
        UiObjectMember *member = members->member;

        if (UiScriptBinding *property = AST::cast<UiScriptBinding *>(member)) {
            if (!property->qualifiedId)
                continue; // better safe than sorry.
            const QString propertyName = toString(property->qualifiedId);
            const QString astValue = cleanupSemicolon(textAt(doc,
                              property->statement->firstSourceLocation(),
                              property->statement->lastSourceLocation()));
            if (isLiteralValue(property)) {
                m_properties.insert(propertyName, QVariant(deEscape(stripQuotes(astValue))));
            } else if (isEnum(property->statement)) { //enum
                 m_properties.insert(propertyName, QVariant(astValue));
                 m_bindingOrEnum.append(propertyName);
            }
        } else if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(member)) { //font { bold: true }
            const QString propertyName = objectDefinition->qualifiedTypeNameId->name.toString();
            if (!propertyName.isEmpty() && !propertyName.at(0).isUpper()) {
                for (UiObjectMemberList *iter = objectDefinition->initializer->members; iter; iter = iter->next) {
                    UiObjectMember *objectMember = iter->member;
                    if (UiScriptBinding *property = cast<UiScriptBinding *>(objectMember)) {
                        const QString propertyNamePart2 = toString(property->qualifiedId);
                        const QString astValue = cleanupSemicolon(textAt(doc,
                            property->statement->firstSourceLocation(),
                            property->statement->lastSourceLocation()));
                        if (isLiteralValue(property)) {
                            m_properties.insert(propertyName + QLatin1Char('.') + propertyNamePart2,
                                                QVariant(deEscape(stripQuotes(astValue))));
                        } else if (isEnum(property->statement)) { //enum
                            m_properties.insert(propertyName + QLatin1Char('.') + propertyNamePart2, QVariant(astValue));
                            m_bindingOrEnum.append(propertyName + QLatin1Char('.') + propertyNamePart2);
                        }
                    }
                }
            }
        } else if (UiObjectBinding* objectBinding = cast<UiObjectBinding *>(member)) {
            UiObjectInitializer *initializer = objectBinding->initializer;
            const QString astValue = cleanupSemicolon(textAt(doc,
                              initializer->lbraceToken,
                              initializer->rbraceToken));
            const QString propertyName = objectBinding->qualifiedId->name.toString();
            m_properties.insert(propertyName, QVariant(astValue));
        }
    }
}

QLinearGradient PropertyReader::parseGradient(const QString &propertyName,  bool *isBound) const
{
    if (!m_doc)
        return QLinearGradient();

    *isBound = false;

    for (UiObjectMemberList *members = m_ast->members; members; members = members->next) {
        UiObjectMember *member = members->member;

        if (UiObjectBinding* objectBinding = cast<UiObjectBinding *>(member)) {
            UiObjectInitializer *initializer = objectBinding->initializer;
            const QString astValue = cleanupSemicolon(textAt(m_doc,
                                                             initializer->lbraceToken,
                                                             initializer->rbraceToken));
            const QString objectPropertyName = objectBinding->qualifiedId->name.toString();
            const QStringRef typeName = objectBinding->qualifiedTypeNameId->name;
            if (objectPropertyName == propertyName && typeName.contains(QLatin1String("Gradient"))) {
                QLinearGradient gradient;
                QVector<QGradientStop> stops;

                for (UiObjectMemberList *members = initializer->members; members; members = members->next) {
                    UiObjectMember *member = members->member;
                    if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(member)) {
                        PropertyReader localParser(m_doc, objectDefinition->initializer);
                        if (localParser.hasProperty(QLatin1String("color")) && localParser.hasProperty(QLatin1String("position"))) {
                            QColor color = QmlJS::toQColor(localParser.readProperty(QLatin1String("color")).toString());
                            qreal position = localParser.readProperty(QLatin1String("position")).toReal();
                            if (localParser.isBindingOrEnum(QLatin1String("color")) || localParser.isBindingOrEnum(QLatin1String("position")))
                                *isBound = true;
                            stops.append( QPair<qreal, QColor>(position, color));
                        }
                    }
                }

                gradient.setStops(stops);
                return gradient;
            }
        }
    }
    return QLinearGradient();
}

} //QmlJS
<commit_msg>QmlJs: Remove dead code<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmljspropertyreader.h"
#include "qmljsdocument.h"
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsutils.h>

#include <QLinearGradient>

namespace QmlJS {

using namespace AST;

namespace {

static inline QString deEscape(const QString &value)
{
    QString result = value;

    result.replace(QLatin1String("\\\\"), QLatin1String("\\"));
    result.replace(QLatin1String("\\\""), QLatin1String("\""));
    result.replace(QLatin1String("\\\t"), QLatin1String("\t"));
    result.replace(QLatin1String("\\\r"), QLatin1String("\r"));
    result.replace(QLatin1String("\\\n"), QLatin1String("\n"));

    return result;
}

static inline QString stripQuotes(const QString &str)
{
    if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
            || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
        return str.mid(1, str.length() - 2);

    return str;
}

static bool isLiteralValue(ExpressionNode *expr)
{
    if (cast<NumericLiteral*>(expr))
        return true;
    else if (cast<StringLiteral*>(expr))
        return true;
    else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr))
        return isLiteralValue(plusExpr->expression);
    else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr))
        return isLiteralValue(minusExpr->expression);
    else if (cast<TrueLiteral*>(expr))
        return true;
    else if (cast<FalseLiteral*>(expr))
        return true;
    else
        return false;
}

static inline bool isLiteralValue(UiScriptBinding *script)
{
    if (!script || !script->statement)
        return false;

    ExpressionStatement *exprStmt = cast<ExpressionStatement *>(script->statement);
    if (exprStmt)
        return isLiteralValue(exprStmt->expression);
    else
        return false;
}

static inline QString textAt(const Document::Ptr doc,
                                  const SourceLocation &from,
                                  const SourceLocation &to)
{
    return doc->source().mid(from.offset, to.end() - from.begin());
}

static bool isEnum(AST::Statement *ast);

bool isEnum(AST::ExpressionNode *ast)
{
    if (!ast)
        return false;

    if (FieldMemberExpression *memberExpr = cast<AST::FieldMemberExpression*>(ast))
        return isEnum(memberExpr->base);
    else if (cast<IdentifierExpression*>(ast))
        return true;
    else
        return false;
}

static bool isEnum(AST::Statement *ast)
{
    if (!ast)
        return false;

    if (ExpressionStatement *exprStmt = cast<ExpressionStatement*>(ast))
        return isEnum(exprStmt->expression);
    return false;
}

static QString cleanupSemicolon(const QString &str)
{
    QString out = str;
    while (out.endsWith(QLatin1Char(';')))
        out.chop(1);
    return out;
}

} // anonymous namespace

PropertyReader::PropertyReader(Document::Ptr doc, AST::UiObjectInitializer *ast)
{
    m_ast = ast;
    m_doc = doc;

    if (!m_doc)
        return;

    for (UiObjectMemberList *members = ast->members; members; members = members->next) {
        UiObjectMember *member = members->member;

        if (UiScriptBinding *property = AST::cast<UiScriptBinding *>(member)) {
            if (!property->qualifiedId)
                continue; // better safe than sorry.
            const QString propertyName = toString(property->qualifiedId);
            const QString astValue = cleanupSemicolon(textAt(doc,
                              property->statement->firstSourceLocation(),
                              property->statement->lastSourceLocation()));
            if (isLiteralValue(property)) {
                m_properties.insert(propertyName, QVariant(deEscape(stripQuotes(astValue))));
            } else if (isEnum(property->statement)) { //enum
                 m_properties.insert(propertyName, QVariant(astValue));
                 m_bindingOrEnum.append(propertyName);
            }
        } else if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(member)) { //font { bold: true }
            const QString propertyName = objectDefinition->qualifiedTypeNameId->name.toString();
            if (!propertyName.isEmpty() && !propertyName.at(0).isUpper()) {
                for (UiObjectMemberList *iter = objectDefinition->initializer->members; iter; iter = iter->next) {
                    UiObjectMember *objectMember = iter->member;
                    if (UiScriptBinding *property = cast<UiScriptBinding *>(objectMember)) {
                        const QString propertyNamePart2 = toString(property->qualifiedId);
                        const QString astValue = cleanupSemicolon(textAt(doc,
                            property->statement->firstSourceLocation(),
                            property->statement->lastSourceLocation()));
                        if (isLiteralValue(property)) {
                            m_properties.insert(propertyName + QLatin1Char('.') + propertyNamePart2,
                                                QVariant(deEscape(stripQuotes(astValue))));
                        } else if (isEnum(property->statement)) { //enum
                            m_properties.insert(propertyName + QLatin1Char('.') + propertyNamePart2, QVariant(astValue));
                            m_bindingOrEnum.append(propertyName + QLatin1Char('.') + propertyNamePart2);
                        }
                    }
                }
            }
        } else if (UiObjectBinding* objectBinding = cast<UiObjectBinding *>(member)) {
            UiObjectInitializer *initializer = objectBinding->initializer;
            const QString astValue = cleanupSemicolon(textAt(doc,
                              initializer->lbraceToken,
                              initializer->rbraceToken));
            const QString propertyName = objectBinding->qualifiedId->name.toString();
            m_properties.insert(propertyName, QVariant(astValue));
        }
    }
}

QLinearGradient PropertyReader::parseGradient(const QString &propertyName,  bool *isBound) const
{
    if (!m_doc)
        return QLinearGradient();

    *isBound = false;

    for (UiObjectMemberList *members = m_ast->members; members; members = members->next) {
        UiObjectMember *member = members->member;

        if (UiObjectBinding* objectBinding = cast<UiObjectBinding *>(member)) {
            UiObjectInitializer *initializer = objectBinding->initializer;
            const QString astValue = cleanupSemicolon(textAt(m_doc,
                                                             initializer->lbraceToken,
                                                             initializer->rbraceToken));
            const QString objectPropertyName = objectBinding->qualifiedId->name.toString();
            const QStringRef typeName = objectBinding->qualifiedTypeNameId->name;
            if (objectPropertyName == propertyName && typeName.contains(QLatin1String("Gradient"))) {
                QLinearGradient gradient;
                QVector<QGradientStop> stops;

                for (UiObjectMemberList *members = initializer->members; members; members = members->next) {
                    UiObjectMember *member = members->member;
                    if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(member)) {
                        PropertyReader localParser(m_doc, objectDefinition->initializer);
                        if (localParser.hasProperty(QLatin1String("color")) && localParser.hasProperty(QLatin1String("position"))) {
                            QColor color = QmlJS::toQColor(localParser.readProperty(QLatin1String("color")).toString());
                            qreal position = localParser.readProperty(QLatin1String("position")).toReal();
                            if (localParser.isBindingOrEnum(QLatin1String("color")) || localParser.isBindingOrEnum(QLatin1String("position")))
                                *isBound = true;
                            stops.append( QPair<qreal, QColor>(position, color));
                        }
                    }
                }

                gradient.setStops(stops);
                return gradient;
            }
        }
    }
    return QLinearGradient();
}

} //QmlJS
<|endoftext|>


<commit_before>/*
*
* Copyright 2017 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker 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.
*
* Orion Context Broker 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 Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <string>
#include <vector>

#include "mongo/client/dbclient.h"

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/sem.h"
#include "common/statistics.h"
#include "common/errorMessages.h"
#include "rest/OrionError.h"
#include "rest/HttpStatusCode.h"
#include "apiTypesV2/Registration.h"
#include "mongoBackend/dbConstants.h"
#include "mongoBackend/safeMongo.h"
#include "mongoBackend/MongoGlobal.h"
#include "mongoBackend/connectionOperations.h"
#include "mongoBackend/mongoRegistrationGet.h"

/* ****************************************************************************
*
* setRegistrationId -
*/
static void setRegistrationId(ngsiv2::Registration* regP, const mongo::BSONObj& r)
{
  regP->id = getFieldF(r, "_id").OID().toString();
}

/* ****************************************************************************
*
* setDescription -
*/
static void setDescription(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  if (r.hasField(dbLabel))
  {
    regP->description         = getStringFieldF(r, dbLabel);
    regP->descriptionProvided = true;
  }
  else
  {
    regP->description         = "";
    regP->descriptionProvided = false;
  }
}

/* ****************************************************************************
*
* setProvider -
*/
static void setProvider(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  regP->provider.http.url = (r.hasField(dbLabel))? getStringFieldF(r, dbLabel): "";

  //
  // FIXME P4: for the moment supportedForwardingMode and legacyForwardingMode are hardwired (i.e. DB is not taken
  // into account for them)
  //
  regP->provider.supportedForwardingMode = ngsiv2::ForwardAll;
  regP->provider.legacyForwardingMode = true;
}

/* ****************************************************************************
*
* setEntities -
*/
static void setEntities(ngsiv2::Registration* regP, const mongo::BSONObj& cr0, const char* dbLabel)
{
  std::vector<mongo::BSONElement>  dbEntityV = getFieldF(cr0, dbLabel).Array();

  for (unsigned int ix = 0; ix < dbEntityV.size(); ++ix)
  {
    ngsiv2::EntID    entity;
    mongo::BSONObj   ce = dbEntityV[ix].embeddedObject();

    if (ce.hasField(REG_ENTITY_ISPATTERN))
    {
      std::string isPattern = getStringFieldF(ce, REG_ENTITY_ISPATTERN);

      if (isPattern == "true")
      {
        entity.idPattern = getStringFieldF(ce, REG_ENTITY_ID);
      }
      else
      {
        entity.id = getStringFieldF(ce, REG_ENTITY_ID);
      }
    }
    else
    {
      entity.id = getStringFieldF(ce, REG_ENTITY_ID);
    }

    if (ce.hasField(REG_ENTITY_ISTYPEPATTERN))
    {
      std::string isPattern = getStringFieldF(ce, REG_ENTITY_ISTYPEPATTERN);

      if (isPattern == "true")
      {
        entity.typePattern = getStringFieldF(ce, REG_ENTITY_TYPE);
      }
      else
      {
        entity.type = getStringFieldF(ce, REG_ENTITY_TYPE);
      }
    }
    else
    {
      entity.type = getStringFieldF(ce, REG_ENTITY_TYPE);
    }

    regP->dataProvided.entities.push_back(entity);
  }
}

/* ****************************************************************************
*
* setAttributes -
*/
static void setAttributes(ngsiv2::Registration* regP, const mongo::BSONObj& cr0, const char* dbLabel)
{
  std::vector<mongo::BSONElement> dbAttributeV = getFieldF(cr0, dbLabel).Array();

  for (unsigned int ix = 0; ix < dbAttributeV.size(); ++ix)
  {
    mongo::BSONObj  aobj     = dbAttributeV[ix].embeddedObject();
    std::string     attrName = getStringFieldF(aobj, REG_ATTRS_NAME);

    if (attrName != "")
    {
      regP->dataProvided.attributes.push_back(attrName);
    }
  }
}

/* ****************************************************************************
*
* setDataProvided -
*
* Make sure there is only ONE "contextRegistration" in the vector
* If we have more than one, then the Registration is made in API V1 as this is not
* possible in V2 and we cannot respond to the request using the current implementation of V2.
* This function will be changed to work in a different way once issue #3044 is dealt with.
*/
static bool setDataProvided(ngsiv2::Registration* regP, const mongo::BSONObj& r, bool arrayAllowed, const char* dbLabel)
{
  std::vector<mongo::BSONElement> crV = getFieldF(r, dbLabel).Array();

  if (crV.size() > 1)
  {
    return false;
  }

  //
  // Extract the first (and only) CR from the contextRegistration vector
  //
  mongo::BSONObj cr0 = crV[0].embeddedObject();

  setEntities(regP, cr0, REG_ENTITIES);
  setAttributes(regP, cr0, REG_ATTRS);
  setProvider(regP, cr0, REG_PROVIDING_APPLICATION);

  return true;
}

/* ****************************************************************************
*
* setExpires -
*/
static void setExpires(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  regP->expires = (r.hasField(dbLabel))? getIntFieldF(r, dbLabel) : -1;
}

/* ****************************************************************************
*
* setStatus -
*/
static void setStatus(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  regP->status = (r.hasField(dbLabel))? getStringFieldF(r, dbLabel): "";
}

/* ****************************************************************************
*
* mongoRegistrationGet -
*/
void mongoRegistrationGet
(
  ngsiv2::Registration*  regP,
  const std::string&     regId,
  const std::string&     tenant,
  const std::string&     servicePath,
  OrionError*            oeP
)
{
  bool         reqSemTaken = false;
  std::string  err;
  mongo::OID   oid;
  StatusCode   sc;

  if (safeGetRegId(regId, &oid, &sc) == false)
  {
    oeP->fill(sc);
    return;
  }

  reqSemTake(__FUNCTION__, "Mongo Get Registration", SemReadOp, &reqSemTaken);

  LM_T(LmtMongo, ("Mongo Get Registration"));

  std::auto_ptr<mongo::DBClientCursor>  cursor;
  mongo::BSONObj                        q;

  // FIXME P0: what about the service path ... ?   See issue #3051
  q = BSON("_id" << oid);

  TIME_STAT_MONGO_READ_WAIT_START();
  mongo::DBClientBase* connection = getMongoConnection();
  if (!collectionQuery(connection, getRegistrationsCollectionName(tenant), q, &cursor, &err))
  {
    releaseMongoConnection(connection);
    TIME_STAT_MONGO_READ_WAIT_STOP();
    reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
    oeP->fill(SccReceiverInternalError, err);
    return;
  }
  TIME_STAT_MONGO_READ_WAIT_STOP();

  /* Process query result */
  if (moreSafe(cursor))
  {
    mongo::BSONObj r;
    if (!nextSafeOrErrorF(cursor, &r, &err))
    {
      releaseMongoConnection(connection);
      LM_E(("Runtime Error (exception in nextSafe(): %s - query: %s)", err.c_str(), q.toString().c_str()));
      reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
      oeP->fill(SccReceiverInternalError, std::string("exception in nextSafe(): ") + err.c_str());
      return;
    }
    LM_T(LmtMongo, ("retrieved document: '%s'", r.toString().c_str()));

    //
    // Fill in the Registration with data retrieved from the data base
    //
    setRegistrationId(regP, r);
    setDescription(regP, r, REG_DESCRIPTION);

    if (setDataProvided(regP, r, false, REG_CONTEXT_REGISTRATION) == false)
    {
      releaseMongoConnection(connection);
      LM_W(("Bad Input (getting registrations with more than one CR is not yet implemented, see issue 3044)"));
      reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
      oeP->fill(SccReceiverInternalError, err);
      return;
    }

    setExpires(regP, r, REG_EXPIRATION);
    setStatus(regP, r, REG_STATUS);

    if (moreSafe(cursor))  // Can only be one ...
    {
      releaseMongoConnection(connection);
      LM_T(LmtMongo, ("more than one registration: '%s'", regId.c_str()));
      reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
      oeP->fill(SccConflict, "");
      return;
    }
  }
  else
  {
    releaseMongoConnection(connection);
    LM_T(LmtMongo, ("registration not found: '%s'", regId.c_str()));
    reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
    oeP->fill(SccContextElementNotFound, ERROR_DESC_NOT_FOUND_REGISTRATION, ERROR_NOT_FOUND);

    return;
  }

  releaseMongoConnection(connection);
  reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);

  oeP->fill(SccOk, "");
}

/* ****************************************************************************
*
* mongoRegistrationsGet -
*/
void mongoRegistrationsGet
(
  std::vector<ngsiv2::Registration>*  regV,
  const std::string&                  tenant,
  const std::vector<std::string>&     servicePathV,
  OrionError*                         oeP
)
{
  bool         reqSemTaken = false;
  std::string  err;
  mongo::OID   oid;
  StatusCode   sc;
  int          limit  = 5000;  // FIXME: Pagination: limit, offset and count are a preparation for it - see mongoGetSubscriptions()
  int          offset = 0;
  long long    count;

  reqSemTake(__FUNCTION__, "Mongo Get Registrations", SemReadOp, &reqSemTaken);

  LM_T(LmtMongo, ("Mongo Get Registrations"));

  std::auto_ptr<mongo::DBClientCursor>  cursor;
  mongo::Query                          q;

  if ((servicePathV.size() != 0) && (servicePathV[0] != "/#"))
  {
    q = BSON(REG_SERVICE_PATH << fillQueryServicePath(servicePathV));
  }

  q.sort(BSON("_id" << 1));

  TIME_STAT_MONGO_READ_WAIT_START();
  mongo::DBClientBase* connection = getMongoConnection();
  if (!collectionRangedQuery(connection, getRegistrationsCollectionName(tenant), q, limit, offset, &cursor, &count, &err))
  {
    releaseMongoConnection(connection);
    TIME_STAT_MONGO_READ_WAIT_STOP();
    reqSemGive(__FUNCTION__, "Mongo Get Registrations", reqSemTaken);
    oeP->fill(SccReceiverInternalError, err);
    return;
  }
  TIME_STAT_MONGO_READ_WAIT_STOP();

  /* Process query result */
  int docs = 0;
  while (moreSafe(cursor))
  {
    mongo::BSONObj        r;
    ngsiv2::Registration  reg;

    if (!nextSafeOrErrorF(cursor, &r, &err))
    {
      LM_E(("Runtime Error (exception in nextSafe(): %s - query: %s)", err.c_str(), q.toString().c_str()));
      continue;
    }

    LM_T(LmtMongo, ("retrieved document [%d]: '%s'", docs, r.toString().c_str()));
    ++docs;

    //
    // Fill in the Registration with data retrieved from the data base
    //
    setRegistrationId(&reg, r);
    setDescription(&reg, r, REG_DESCRIPTION);

    if (setDataProvided(&reg, r, false, REG_CONTEXT_REGISTRATION) == false)
    {
      releaseMongoConnection(connection);
      LM_W(("Bad Input (getting registrations with more than one CR is not yet implemented, see issue 3044)"));
      reqSemGive(__FUNCTION__, "Mongo Get Registrations", reqSemTaken);
      oeP->fill(SccReceiverInternalError, err);
      return;
    }

    setExpires(&reg, r, REG_EXPIRATION);
    setStatus(&reg, r, REG_STATUS);

    // FIXME PR: What about the Service Path of the Registration ... ?
    regV->push_back(reg);
  }

  releaseMongoConnection(connection);
  reqSemGive(__FUNCTION__, "Mongo Get Registrations", reqSemTaken);

  oeP->fill(SccOk, "");
}
<commit_msg>exact match with servicePathV[0] + FIXME removed<commit_after>/*
*
* Copyright 2017 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker 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.
*
* Orion Context Broker 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 Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <string>
#include <vector>

#include "mongo/client/dbclient.h"

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/sem.h"
#include "common/statistics.h"
#include "common/errorMessages.h"
#include "rest/OrionError.h"
#include "rest/HttpStatusCode.h"
#include "apiTypesV2/Registration.h"
#include "mongoBackend/dbConstants.h"
#include "mongoBackend/safeMongo.h"
#include "mongoBackend/MongoGlobal.h"
#include "mongoBackend/connectionOperations.h"
#include "mongoBackend/mongoRegistrationGet.h"

/* ****************************************************************************
*
* setRegistrationId -
*/
static void setRegistrationId(ngsiv2::Registration* regP, const mongo::BSONObj& r)
{
  regP->id = getFieldF(r, "_id").OID().toString();
}

/* ****************************************************************************
*
* setDescription -
*/
static void setDescription(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  if (r.hasField(dbLabel))
  {
    regP->description         = getStringFieldF(r, dbLabel);
    regP->descriptionProvided = true;
  }
  else
  {
    regP->description         = "";
    regP->descriptionProvided = false;
  }
}

/* ****************************************************************************
*
* setProvider -
*/
static void setProvider(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  regP->provider.http.url = (r.hasField(dbLabel))? getStringFieldF(r, dbLabel): "";

  //
  // FIXME P4: for the moment supportedForwardingMode and legacyForwardingMode are hardwired (i.e. DB is not taken
  // into account for them)
  //
  regP->provider.supportedForwardingMode = ngsiv2::ForwardAll;
  regP->provider.legacyForwardingMode = true;
}

/* ****************************************************************************
*
* setEntities -
*/
static void setEntities(ngsiv2::Registration* regP, const mongo::BSONObj& cr0, const char* dbLabel)
{
  std::vector<mongo::BSONElement>  dbEntityV = getFieldF(cr0, dbLabel).Array();

  for (unsigned int ix = 0; ix < dbEntityV.size(); ++ix)
  {
    ngsiv2::EntID    entity;
    mongo::BSONObj   ce = dbEntityV[ix].embeddedObject();

    if (ce.hasField(REG_ENTITY_ISPATTERN))
    {
      std::string isPattern = getStringFieldF(ce, REG_ENTITY_ISPATTERN);

      if (isPattern == "true")
      {
        entity.idPattern = getStringFieldF(ce, REG_ENTITY_ID);
      }
      else
      {
        entity.id = getStringFieldF(ce, REG_ENTITY_ID);
      }
    }
    else
    {
      entity.id = getStringFieldF(ce, REG_ENTITY_ID);
    }

    if (ce.hasField(REG_ENTITY_ISTYPEPATTERN))
    {
      std::string isPattern = getStringFieldF(ce, REG_ENTITY_ISTYPEPATTERN);

      if (isPattern == "true")
      {
        entity.typePattern = getStringFieldF(ce, REG_ENTITY_TYPE);
      }
      else
      {
        entity.type = getStringFieldF(ce, REG_ENTITY_TYPE);
      }
    }
    else
    {
      entity.type = getStringFieldF(ce, REG_ENTITY_TYPE);
    }

    regP->dataProvided.entities.push_back(entity);
  }
}

/* ****************************************************************************
*
* setAttributes -
*/
static void setAttributes(ngsiv2::Registration* regP, const mongo::BSONObj& cr0, const char* dbLabel)
{
  std::vector<mongo::BSONElement> dbAttributeV = getFieldF(cr0, dbLabel).Array();

  for (unsigned int ix = 0; ix < dbAttributeV.size(); ++ix)
  {
    mongo::BSONObj  aobj     = dbAttributeV[ix].embeddedObject();
    std::string     attrName = getStringFieldF(aobj, REG_ATTRS_NAME);

    if (attrName != "")
    {
      regP->dataProvided.attributes.push_back(attrName);
    }
  }
}

/* ****************************************************************************
*
* setDataProvided -
*
* Make sure there is only ONE "contextRegistration" in the vector
* If we have more than one, then the Registration is made in API V1 as this is not
* possible in V2 and we cannot respond to the request using the current implementation of V2.
* This function will be changed to work in a different way once issue #3044 is dealt with.
*/
static bool setDataProvided(ngsiv2::Registration* regP, const mongo::BSONObj& r, bool arrayAllowed, const char* dbLabel)
{
  std::vector<mongo::BSONElement> crV = getFieldF(r, dbLabel).Array();

  if (crV.size() > 1)
  {
    return false;
  }

  //
  // Extract the first (and only) CR from the contextRegistration vector
  //
  mongo::BSONObj cr0 = crV[0].embeddedObject();

  setEntities(regP, cr0, REG_ENTITIES);
  setAttributes(regP, cr0, REG_ATTRS);
  setProvider(regP, cr0, REG_PROVIDING_APPLICATION);

  return true;
}

/* ****************************************************************************
*
* setExpires -
*/
static void setExpires(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  regP->expires = (r.hasField(dbLabel))? getIntFieldF(r, dbLabel) : -1;
}

/* ****************************************************************************
*
* setStatus -
*/
static void setStatus(ngsiv2::Registration* regP, const mongo::BSONObj& r, const char* dbLabel)
{
  regP->status = (r.hasField(dbLabel))? getStringFieldF(r, dbLabel): "";
}

/* ****************************************************************************
*
* mongoRegistrationGet -
*/
void mongoRegistrationGet
(
  ngsiv2::Registration*  regP,
  const std::string&     regId,
  const std::string&     tenant,
  const std::string&     servicePath,
  OrionError*            oeP
)
{
  bool         reqSemTaken = false;
  std::string  err;
  mongo::OID   oid;
  StatusCode   sc;

  if (safeGetRegId(regId, &oid, &sc) == false)
  {
    oeP->fill(sc);
    return;
  }

  reqSemTake(__FUNCTION__, "Mongo Get Registration", SemReadOp, &reqSemTaken);

  LM_T(LmtMongo, ("Mongo Get Registration"));

  std::auto_ptr<mongo::DBClientCursor>  cursor;
  mongo::BSONObj                        q;

  q = BSON("_id" << oid);

  TIME_STAT_MONGO_READ_WAIT_START();
  mongo::DBClientBase* connection = getMongoConnection();
  if (!collectionQuery(connection, getRegistrationsCollectionName(tenant), q, &cursor, &err))
  {
    releaseMongoConnection(connection);
    TIME_STAT_MONGO_READ_WAIT_STOP();
    reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
    oeP->fill(SccReceiverInternalError, err);
    return;
  }
  TIME_STAT_MONGO_READ_WAIT_STOP();

  /* Process query result */
  if (moreSafe(cursor))
  {
    mongo::BSONObj r;
    if (!nextSafeOrErrorF(cursor, &r, &err))
    {
      releaseMongoConnection(connection);
      LM_E(("Runtime Error (exception in nextSafe(): %s - query: %s)", err.c_str(), q.toString().c_str()));
      reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
      oeP->fill(SccReceiverInternalError, std::string("exception in nextSafe(): ") + err.c_str());
      return;
    }
    LM_T(LmtMongo, ("retrieved document: '%s'", r.toString().c_str()));

    //
    // Fill in the Registration with data retrieved from the data base
    //
    setRegistrationId(regP, r);
    setDescription(regP, r, REG_DESCRIPTION);

    if (setDataProvided(regP, r, false, REG_CONTEXT_REGISTRATION) == false)
    {
      releaseMongoConnection(connection);
      LM_W(("Bad Input (getting registrations with more than one CR is not yet implemented, see issue 3044)"));
      reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
      oeP->fill(SccReceiverInternalError, err);
      return;
    }

    setExpires(regP, r, REG_EXPIRATION);
    setStatus(regP, r, REG_STATUS);

    if (moreSafe(cursor))  // Can only be one ...
    {
      releaseMongoConnection(connection);
      LM_T(LmtMongo, ("more than one registration: '%s'", regId.c_str()));
      reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
      oeP->fill(SccConflict, "");
      return;
    }
  }
  else
  {
    releaseMongoConnection(connection);
    LM_T(LmtMongo, ("registration not found: '%s'", regId.c_str()));
    reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);
    oeP->fill(SccContextElementNotFound, ERROR_DESC_NOT_FOUND_REGISTRATION, ERROR_NOT_FOUND);

    return;
  }

  releaseMongoConnection(connection);
  reqSemGive(__FUNCTION__, "Mongo Get Registration", reqSemTaken);

  oeP->fill(SccOk, "");
}

/* ****************************************************************************
*
* mongoRegistrationsGet -
*/
void mongoRegistrationsGet
(
  std::vector<ngsiv2::Registration>*  regV,
  const std::string&                  tenant,
  const std::vector<std::string>&     servicePathV,
  OrionError*                         oeP
)
{
  bool         reqSemTaken = false;
  std::string  err;
  mongo::OID   oid;
  StatusCode   sc;
  int          limit  = 5000;  // FIXME: Pagination: limit, offset and count are a preparation for it - see mongoGetSubscriptions()
  int          offset = 0;
  long long    count;

  reqSemTake(__FUNCTION__, "Mongo Get Registrations", SemReadOp, &reqSemTaken);

  LM_T(LmtMongo, ("Mongo Get Registrations"));

  std::auto_ptr<mongo::DBClientCursor>  cursor;
  mongo::Query                          q;

  // FIXME P4: Return error if more than one service path in servicePathV ?
  if ((servicePathV.size() != 0) && (servicePathV[0] != "/#"))
  {
    q = BSON(REG_SERVICE_PATH << servicePathV[0]);
  }

  q.sort(BSON("_id" << 1));

  TIME_STAT_MONGO_READ_WAIT_START();
  mongo::DBClientBase* connection = getMongoConnection();
  if (!collectionRangedQuery(connection, getRegistrationsCollectionName(tenant), q, limit, offset, &cursor, &count, &err))
  {
    releaseMongoConnection(connection);
    TIME_STAT_MONGO_READ_WAIT_STOP();
    reqSemGive(__FUNCTION__, "Mongo Get Registrations", reqSemTaken);
    oeP->fill(SccReceiverInternalError, err);
    return;
  }
  TIME_STAT_MONGO_READ_WAIT_STOP();

  /* Process query result */
  int docs = 0;
  while (moreSafe(cursor))
  {
    mongo::BSONObj        r;
    ngsiv2::Registration  reg;

    if (!nextSafeOrErrorF(cursor, &r, &err))
    {
      LM_E(("Runtime Error (exception in nextSafe(): %s - query: %s)", err.c_str(), q.toString().c_str()));
      continue;
    }

    LM_T(LmtMongo, ("retrieved document [%d]: '%s'", docs, r.toString().c_str()));
    ++docs;

    //
    // Fill in the Registration with data retrieved from the data base
    //
    setRegistrationId(&reg, r);
    setDescription(&reg, r, REG_DESCRIPTION);

    if (setDataProvided(&reg, r, false, REG_CONTEXT_REGISTRATION) == false)
    {
      releaseMongoConnection(connection);
      LM_W(("Bad Input (getting registrations with more than one CR is not yet implemented, see issue 3044)"));
      reqSemGive(__FUNCTION__, "Mongo Get Registrations", reqSemTaken);
      oeP->fill(SccReceiverInternalError, err);
      return;
    }

    setExpires(&reg, r, REG_EXPIRATION);
    setStatus(&reg, r, REG_STATUS);

    regV->push_back(reg);
  }

  releaseMongoConnection(connection);
  reqSemGive(__FUNCTION__, "Mongo Get Registrations", reqSemTaken);

  oeP->fill(SccOk, "");
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016, Simula Research Laboratory
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#define png_infopp_NULL (png_infopp)NULL
#define int_p_NULL (int*)NULL
#include <boost/gil/extension/io/png_io.hpp>

#include "cctag/utils/FileDebug.hpp"
#include "cctag/utils/VisualDebug.hpp"
#include "cctag/utils/Exceptions.hpp"
#include "cctag/Detection.hpp"
#include "CmdLine.hpp"

#ifdef WITH_CUDA
#include "cuda/device_prop.hpp"
#include "cuda/debug_macros.hpp"
#endif // WITH_CUDA

#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem.hpp>
#include <boost/progress.hpp>
#include <boost/exception/all.hpp>
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

#include <opencv/cv.h>
#include <opencv2/videoio.hpp>
#include <opencv2/core/core.hpp>
#include "opencv2/opencv.hpp"

#include <sstream>
#include <iostream>
#include <string>
#include <fstream>
#include <exception>
#include <regex>

#include <tbb/tbb.h>

#define PRINT_TO_CERR

using namespace cctag;
using boost::timer;

using namespace boost::gil;
namespace bfs = boost::filesystem;

/**
 * @brief Check if a string is an integer number.
 *
 * @param[in] s The string to check.
 * @return Return true if the string is an integer number
 */
bool isInteger(std::string s)
{
  std::regex e("^-?\\d+");
  return std::regex_match(s, e);
}

/**
 * @brief Draw the detected marker int the given image. The markers are drawn as a
 * circle centered in the center of the marker and with its id. It draws the
 * well identified markers in green, the unknown / badly detected markers in red.
 *
 * @param[in] markers The list of markers to draw.
 * @param[out] image The image in which to draw the markers.
 */
void drawMarkers(const boost::ptr_list<CCTag> &markers, cv::Mat &image)
{
  BOOST_FOREACH(const cctag::CCTag & marker, markers)
  {
    const cv::Point center = cv::Point(marker.x(), marker.y());
    const int radius = 10;
    if(marker.getStatus() == 1)
    {
      const cv::Scalar color = cv::Scalar(0, 255, 0 , 255);
      cv::circle(image, center, radius, color, 3);
      cv::putText(image, std::to_string(marker.id()), center, cv::FONT_HERSHEY_SIMPLEX, 5, color, 3);
    }
    else
    {
      const cv::Scalar color = cv::Scalar(0, 0, 255 , 255);
      cv::circle(image, center, radius, color, 2);
      cv::putText(image, std::to_string(marker.id()), center, cv::FONT_HERSHEY_SIMPLEX, 4, color, 3);
    }

  }
}

void detection(std::size_t frameId,
               int pipeId,
               const cv::Mat & src,
               const cctag::Parameters & params,
               const cctag::CCTagMarkersBank & bank,
               boost::ptr_list<CCTag> &markers,
               std::ostream & output,
               std::string debugFileName = "")
{

  if(debugFileName == "")
  {
    debugFileName = "00000";
  }

  // Process markers detection
  boost::timer t;

  CCTagVisualDebug::instance().initBackgroundImage(src);
  CCTagVisualDebug::instance().setImageFileName(debugFileName);
  CCTagFileDebug::instance().setPath(CCTagVisualDebug::instance().getPath());

  static cctag::logtime::Mgmt* durations = 0;

  //Call the main CCTag detection function
  cctagDetection(markers, pipeId, frameId, src, params, bank, true, durations);

  if(durations)
  {
    durations->print(std::cerr);
  }

  CCTagFileDebug::instance().outPutAllSessions();
  CCTagFileDebug::instance().clearSessions();
  CCTagVisualDebug::instance().outPutAllSessions();
  CCTagVisualDebug::instance().clearSessions();

  std::cout << "Total time: " << t.elapsed() << std::endl;
  CCTAG_COUT_NOENDL("Id : ");

  std::size_t counter = 0;
  std::size_t nMarkers = 0;
  output << "#frame " << frameId << '\n';
  output << "Detected " << markers.size() << " candidates" << '\n';

  BOOST_FOREACH(const cctag::CCTag & marker, markers)
  {
    output << marker.x() << " " << marker.y() << " " << marker.id() << " " << marker.getStatus() << '\n';
    ++counter;
    if(marker.getStatus() == 1)
      ++nMarkers;
  }

  counter = 0;
  BOOST_FOREACH(const cctag::CCTag & marker, markers)
  {
    if(counter == 0)
    {
      CCTAG_COUT_NOENDL(marker.id() + 1);
    }
    else
    {
      CCTAG_COUT_NOENDL(", " << marker.id() + 1);
    }
    ++counter;
  }

  std::cout << std::endl << nMarkers << " markers detected and identified" << std::endl;
}

/*************************************************************/
/*                    Main entry                             */

/*************************************************************/
int main(int argc, char** argv)
{
  CmdLine cmdline;

  if(cmdline.parse(argc, argv) == false)
  {
    cmdline.usage(argv[0]);
    return EXIT_FAILURE;
  }

  cmdline.print(argv[0]);

  bool useCamera = false;

  // Check input path
  if(!cmdline._filename.empty())
  {
    if(isInteger(cmdline._filename))
    {
      useCamera = true;
    }
    else if(!boost::filesystem::exists(cmdline._filename))
    {
      std::cerr << std::endl
              << "The input file \"" << cmdline._filename << "\" is missing" << std::endl;
      return EXIT_FAILURE;
    }
  }
  else
  {
    std::cerr << std::endl
            << "An input file is required" << std::endl;
    cmdline.usage(argv[0]);
    return EXIT_FAILURE;
  }

#ifdef WITH_CUDA
  popart::pop_cuda_only_sync_calls(cmdline._switchSync);
#endif

  // Check the (optional) parameters path
  const std::size_t nCrowns = std::atoi(cmdline._nCrowns.c_str());
  cctag::Parameters params(nCrowns);

  if(!cmdline._paramsFilename.empty())
  {
    if(!boost::filesystem::exists(cmdline._paramsFilename))
    {
      std::cerr << std::endl
              << "The input file \"" << cmdline._paramsFilename << "\" is missing" << std::endl;
      return EXIT_FAILURE;
    }

    // Read the parameter file provided by the user
    std::ifstream ifs(cmdline._paramsFilename);
    boost::archive::xml_iarchive ia(ifs);
    ia >> boost::serialization::make_nvp("CCTagsParams", params);
    CCTAG_COUT(params._nCrowns);
    CCTAG_COUT(nCrowns);
    assert(nCrowns == params._nCrowns);
  }
  else
  {
    // Use the default parameters and save them in defaultParameters.xml
    cmdline._paramsFilename = "defaultParameters.xml";
    std::ofstream ofs(cmdline._paramsFilename);
    boost::archive::xml_oarchive oa(ofs);
    oa << boost::serialization::make_nvp("CCTagsParams", params);
    CCTAG_COUT("Parameter file not provided. Default parameters are used.");
  }

  CCTagMarkersBank bank(params._nCrowns);
  if(!cmdline._cctagBankFilename.empty())
  {
    bank = CCTagMarkersBank(cmdline._cctagBankFilename);
  }

#ifdef WITH_CUDA
  if(cmdline._useCuda)
  {
    params.setUseCuda(true);
  }
  else
  {
    params.setUseCuda(false);
  }

  if(cmdline._debugDir != "")
  {
    params.setDebugDir(cmdline._debugDir);
  }

  popart::device_prop_t deviceInfo(false);
#endif // WITH_CUDA

  bfs::path myPath(cmdline._filename);
  std::string ext(myPath.extension().string());

  const bfs::path parentPath(myPath.parent_path() == "" ? "." : myPath.parent_path());
  std::string outputFileName;
  if(!bfs::is_directory(myPath))
  {
    CCTagVisualDebug::instance().initializeFolders(parentPath, cmdline._outputFolderName, params._nCrowns);
    outputFileName = parentPath.string() + "/" + cmdline._outputFolderName + "/cctag" + std::to_string(nCrowns) + "CC.out";
  }
  else
  {
    CCTagVisualDebug::instance().initializeFolders(myPath, cmdline._outputFolderName, params._nCrowns);
    outputFileName = myPath.string() + "/" + cmdline._outputFolderName + "/cctag" + std::to_string(nCrowns) + "CC.out";
  }
  std::ofstream outputFile;
  outputFile.open(outputFileName);

  if((ext == ".png") || (ext == ".jpg") || (ext == ".PNG") || (ext == ".JPG"))
  {

    std::cout << "******************* Image mode **********************" << std::endl;

    POP_INFO("looking at image " << myPath.string());

    // Gray scale conversion
    cv::Mat src = cv::imread(cmdline._filename);
    cv::Mat graySrc;
    cv::cvtColor(src, graySrc, CV_BGR2GRAY);

    const int pipeId = 0;
    boost::ptr_list<CCTag> markers;
#ifdef PRINT_TO_CERR
    detection(0, pipeId, graySrc, params, bank, markers, std::cerr, myPath.stem().string());
#else
    detection(0, pipeId, graySrc, params, bank, markers, outputFile, myPath.stem().string());
#endif
  }
  else if(ext == ".avi" || ext == ".mov" || useCamera)
  {
    CCTAG_COUT("*** Video mode ***");
    POP_INFO("looking at video " << myPath.string());

    // open video and check
    cv::VideoCapture video;
    if(useCamera)
      video.open(std::atoi(cmdline._filename.c_str()));
    else
      video.open(cmdline._filename);

    if(!video.isOpened())
    {
      CCTAG_COUT("Unable to open the video : " << cmdline._filename);
      return EXIT_FAILURE;
    }

    const std::string windowName = "Detection result";
    cv::namedWindow(windowName, cv::WINDOW_NORMAL);

    std::cerr << "Starting to read video frames" << std::endl;
    std::size_t frameId = 0;

    // time to wait in milliseconds for keyboard input, used to switch from
    // live to debug mode
    int delay = 10;

    while(true)
    {
      cv::Mat frame;
      video >> frame;
      if(frame.empty())
        break;

      cv::Mat imgGray;

      if(frame.channels() == 3 || frame.channels() == 4)
        cv::cvtColor(frame, imgGray, cv::COLOR_BGR2GRAY);
      else
        frame.copyTo(imgGray);

      boost::timer t;

      // Set the output folder
      std::stringstream outFileName;
      outFileName << std::setfill('0') << std::setw(5) << frameId;

      boost::ptr_list<CCTag> markers;

      // Invert the image for the projection scenario
      //cv::Mat imgGrayInverted;
      //bitwise_not ( imgGray, imgGrayInverted );

      // Call the CCTag detection
      const int pipeId = 0;
#ifdef PRINT_TO_CERR
      detection(frameId, pipeId, imgGray, params, bank, markers, std::cerr, outFileName.str());
#else
      detection(frameId, pipeId, imgGray, params, bank, markers, outputFile, outFileName.str());
#endif

      // if the original image is b/w convert it to BGRA so we can draw colors
      if(frame.channels() == 1)
        cv::cvtColor(imgGray, frame, cv::COLOR_GRAY2BGRA);

      drawMarkers(markers, frame);
      cv::imshow(windowName, frame);
      if( cv::waitKey(delay) == 27 ) break;
      char key = (char) cv::waitKey(delay);
      // stop capturing by pressing ESC
      if(key == 27)
        break;
      if(key == 'l' || key == 'L')
        delay = 10;
      // delay = 0 will wait for a key to be pressed
      if(key == 'd' || key == 'D')
        delay = 0;

      ++frameId;
    }

  }
  else if(bfs::is_directory(myPath))
  {
    CCTAG_COUT("*** Image sequence mode ***");

    std::vector<bfs::path> vFileInFolder;

    std::copy(bfs::directory_iterator(myPath), bfs::directory_iterator(), std::back_inserter(vFileInFolder)); // is directory_entry, which is
    std::sort(vFileInFolder.begin(), vFileInFolder.end());

    std::size_t frameId = 0;

    std::map<int, bfs::path> files[2];
    for(const auto & fileInFolder : vFileInFolder)
    {
      files[frameId & 1].insert(std::pair<int, bfs::path>(frameId, fileInFolder));
      frameId++;
    }

    tbb::parallel_for(0, 2, [&](size_t fileListIdx)
    {
      for(const auto & fileInFolder : files[fileListIdx])
      {
        const std::string subExt(bfs::extension(fileInFolder.second));

        if((subExt == ".png") || (subExt == ".jpg") || (subExt == ".PNG") || (subExt == ".JPG"))
        {

          std::cerr << "Processing image " << fileInFolder.second.string() << std::endl;

          cv::Mat src;
          src = cv::imread(fileInFolder.second.string());

          cv::Mat imgGray;
          cv::cvtColor(src, imgGray, CV_BGR2GRAY);

          // Call the CCTag detection
          int pipeId = (fileInFolder.first & 1);
          boost::ptr_list<CCTag> markers;
#ifdef PRINT_TO_CERR
          detection(fileInFolder.first, pipeId, imgGray, params, bank, markers, std::cerr, fileInFolder.second.stem().string());
#else
          detection(fileInFolder.first, pipeId, imgGray, params, bank, markers, outputFile, fileInFolder.second.stem().string());
#endif
          std::cerr << "Done processing image " << fileInFolder.second.string() << std::endl;
        }
      }
    });
  }
  else
  {
    throw std::logic_error("Unrecognized input.");
  }
  outputFile.close();
  return EXIT_SUCCESS;
}

<commit_msg>[applications] fix isInteger()<commit_after>/*
 * Copyright 2016, Simula Research Laboratory
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#define png_infopp_NULL (png_infopp)NULL
#define int_p_NULL (int*)NULL
#include <boost/gil/extension/io/png_io.hpp>

#include "cctag/utils/FileDebug.hpp"
#include "cctag/utils/VisualDebug.hpp"
#include "cctag/utils/Exceptions.hpp"
#include "cctag/Detection.hpp"
#include "CmdLine.hpp"

#ifdef WITH_CUDA
#include "cuda/device_prop.hpp"
#include "cuda/debug_macros.hpp"
#endif // WITH_CUDA

#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem.hpp>
#include <boost/progress.hpp>
#include <boost/exception/all.hpp>
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

#include <opencv/cv.h>
#include <opencv2/videoio.hpp>
#include <opencv2/core/core.hpp>
#include "opencv2/opencv.hpp"

#include <sstream>
#include <iostream>
#include <string>
#include <fstream>
#include <exception>
#include <regex>

#include <tbb/tbb.h>

#define PRINT_TO_CERR

using namespace cctag;
using boost::timer;

using namespace boost::gil;
namespace bfs = boost::filesystem;

/**
 * @brief Check if a string is an integer number.
 *
 * @param[in] s The string to check.
 * @return Return true if the string is an integer number
 */
bool isInteger(std::string &s)
{
  std::regex e("^-?\\d+");
  return std::regex_match(s, e);
}

/**
 * @brief Draw the detected marker int the given image. The markers are drawn as a
 * circle centered in the center of the marker and with its id. It draws the
 * well identified markers in green, the unknown / badly detected markers in red.
 *
 * @param[in] markers The list of markers to draw.
 * @param[out] image The image in which to draw the markers.
 */
void drawMarkers(const boost::ptr_list<CCTag> &markers, cv::Mat &image)
{
  BOOST_FOREACH(const cctag::CCTag & marker, markers)
  {
    const cv::Point center = cv::Point(marker.x(), marker.y());
    const int radius = 10;
    if(marker.getStatus() == 1)
    {
      const cv::Scalar color = cv::Scalar(0, 255, 0 , 255);
      cv::circle(image, center, radius, color, 3);
      cv::putText(image, std::to_string(marker.id()), center, cv::FONT_HERSHEY_SIMPLEX, 5, color, 3);
    }
    else
    {
      const cv::Scalar color = cv::Scalar(0, 0, 255 , 255);
      cv::circle(image, center, radius, color, 2);
      cv::putText(image, std::to_string(marker.id()), center, cv::FONT_HERSHEY_SIMPLEX, 4, color, 3);
    }

  }
}

void detection(std::size_t frameId,
               int pipeId,
               const cv::Mat & src,
               const cctag::Parameters & params,
               const cctag::CCTagMarkersBank & bank,
               boost::ptr_list<CCTag> &markers,
               std::ostream & output,
               std::string debugFileName = "")
{

  if(debugFileName == "")
  {
    debugFileName = "00000";
  }

  // Process markers detection
  boost::timer t;

  CCTagVisualDebug::instance().initBackgroundImage(src);
  CCTagVisualDebug::instance().setImageFileName(debugFileName);
  CCTagFileDebug::instance().setPath(CCTagVisualDebug::instance().getPath());

  static cctag::logtime::Mgmt* durations = 0;

  //Call the main CCTag detection function
  cctagDetection(markers, pipeId, frameId, src, params, bank, true, durations);

  if(durations)
  {
    durations->print(std::cerr);
  }

  CCTagFileDebug::instance().outPutAllSessions();
  CCTagFileDebug::instance().clearSessions();
  CCTagVisualDebug::instance().outPutAllSessions();
  CCTagVisualDebug::instance().clearSessions();

  std::cout << "Total time: " << t.elapsed() << std::endl;
  CCTAG_COUT_NOENDL("Id : ");

  std::size_t counter = 0;
  std::size_t nMarkers = 0;
  output << "#frame " << frameId << '\n';
  output << "Detected " << markers.size() << " candidates" << '\n';

  BOOST_FOREACH(const cctag::CCTag & marker, markers)
  {
    output << marker.x() << " " << marker.y() << " " << marker.id() << " " << marker.getStatus() << '\n';
    ++counter;
    if(marker.getStatus() == 1)
      ++nMarkers;
  }

  counter = 0;
  BOOST_FOREACH(const cctag::CCTag & marker, markers)
  {
    if(counter == 0)
    {
      CCTAG_COUT_NOENDL(marker.id() + 1);
    }
    else
    {
      CCTAG_COUT_NOENDL(", " << marker.id() + 1);
    }
    ++counter;
  }

  std::cout << std::endl << nMarkers << " markers detected and identified" << std::endl;
}

/*************************************************************/
/*                    Main entry                             */

/*************************************************************/
int main(int argc, char** argv)
{
  CmdLine cmdline;

  if(cmdline.parse(argc, argv) == false)
  {
    cmdline.usage(argv[0]);
    return EXIT_FAILURE;
  }

  cmdline.print(argv[0]);

  bool useCamera = false;

  // Check input path
  if(!cmdline._filename.empty())
  {
    if(isInteger(cmdline._filename))
    {
      useCamera = true;
    }
    else if(!boost::filesystem::exists(cmdline._filename))
    {
      std::cerr << std::endl
              << "The input file \"" << cmdline._filename << "\" is missing" << std::endl;
      return EXIT_FAILURE;
    }
  }
  else
  {
    std::cerr << std::endl
            << "An input file is required" << std::endl;
    cmdline.usage(argv[0]);
    return EXIT_FAILURE;
  }

#ifdef WITH_CUDA
  popart::pop_cuda_only_sync_calls(cmdline._switchSync);
#endif

  // Check the (optional) parameters path
  const std::size_t nCrowns = std::atoi(cmdline._nCrowns.c_str());
  cctag::Parameters params(nCrowns);

  if(!cmdline._paramsFilename.empty())
  {
    if(!boost::filesystem::exists(cmdline._paramsFilename))
    {
      std::cerr << std::endl
              << "The input file \"" << cmdline._paramsFilename << "\" is missing" << std::endl;
      return EXIT_FAILURE;
    }

    // Read the parameter file provided by the user
    std::ifstream ifs(cmdline._paramsFilename);
    boost::archive::xml_iarchive ia(ifs);
    ia >> boost::serialization::make_nvp("CCTagsParams", params);
    CCTAG_COUT(params._nCrowns);
    CCTAG_COUT(nCrowns);
    assert(nCrowns == params._nCrowns);
  }
  else
  {
    // Use the default parameters and save them in defaultParameters.xml
    cmdline._paramsFilename = "defaultParameters.xml";
    std::ofstream ofs(cmdline._paramsFilename);
    boost::archive::xml_oarchive oa(ofs);
    oa << boost::serialization::make_nvp("CCTagsParams", params);
    CCTAG_COUT("Parameter file not provided. Default parameters are used.");
  }

  CCTagMarkersBank bank(params._nCrowns);
  if(!cmdline._cctagBankFilename.empty())
  {
    bank = CCTagMarkersBank(cmdline._cctagBankFilename);
  }

#ifdef WITH_CUDA
  if(cmdline._useCuda)
  {
    params.setUseCuda(true);
  }
  else
  {
    params.setUseCuda(false);
  }

  if(cmdline._debugDir != "")
  {
    params.setDebugDir(cmdline._debugDir);
  }

  popart::device_prop_t deviceInfo(false);
#endif // WITH_CUDA

  bfs::path myPath(cmdline._filename);
  std::string ext(myPath.extension().string());

  const bfs::path parentPath(myPath.parent_path() == "" ? "." : myPath.parent_path());
  std::string outputFileName;
  if(!bfs::is_directory(myPath))
  {
    CCTagVisualDebug::instance().initializeFolders(parentPath, cmdline._outputFolderName, params._nCrowns);
    outputFileName = parentPath.string() + "/" + cmdline._outputFolderName + "/cctag" + std::to_string(nCrowns) + "CC.out";
  }
  else
  {
    CCTagVisualDebug::instance().initializeFolders(myPath, cmdline._outputFolderName, params._nCrowns);
    outputFileName = myPath.string() + "/" + cmdline._outputFolderName + "/cctag" + std::to_string(nCrowns) + "CC.out";
  }
  std::ofstream outputFile;
  outputFile.open(outputFileName);

  if((ext == ".png") || (ext == ".jpg") || (ext == ".PNG") || (ext == ".JPG"))
  {

    std::cout << "******************* Image mode **********************" << std::endl;

    POP_INFO("looking at image " << myPath.string());

    // Gray scale conversion
    cv::Mat src = cv::imread(cmdline._filename);
    cv::Mat graySrc;
    cv::cvtColor(src, graySrc, CV_BGR2GRAY);

    const int pipeId = 0;
    boost::ptr_list<CCTag> markers;
#ifdef PRINT_TO_CERR
    detection(0, pipeId, graySrc, params, bank, markers, std::cerr, myPath.stem().string());
#else
    detection(0, pipeId, graySrc, params, bank, markers, outputFile, myPath.stem().string());
#endif
  }
  else if(ext == ".avi" || ext == ".mov" || useCamera)
  {
    CCTAG_COUT("*** Video mode ***");
    POP_INFO("looking at video " << myPath.string());

    // open video and check
    cv::VideoCapture video;
    if(useCamera)
      video.open(std::atoi(cmdline._filename.c_str()));
    else
      video.open(cmdline._filename);

    if(!video.isOpened())
    {
      CCTAG_COUT("Unable to open the video : " << cmdline._filename);
      return EXIT_FAILURE;
    }

    const std::string windowName = "Detection result";
    cv::namedWindow(windowName, cv::WINDOW_NORMAL);

    std::cerr << "Starting to read video frames" << std::endl;
    std::size_t frameId = 0;

    // time to wait in milliseconds for keyboard input, used to switch from
    // live to debug mode
    int delay = 10;

    while(true)
    {
      cv::Mat frame;
      video >> frame;
      if(frame.empty())
        break;

      cv::Mat imgGray;

      if(frame.channels() == 3 || frame.channels() == 4)
        cv::cvtColor(frame, imgGray, cv::COLOR_BGR2GRAY);
      else
        frame.copyTo(imgGray);

      boost::timer t;

      // Set the output folder
      std::stringstream outFileName;
      outFileName << std::setfill('0') << std::setw(5) << frameId;

      boost::ptr_list<CCTag> markers;

      // Invert the image for the projection scenario
      //cv::Mat imgGrayInverted;
      //bitwise_not ( imgGray, imgGrayInverted );

      // Call the CCTag detection
      const int pipeId = 0;
#ifdef PRINT_TO_CERR
      detection(frameId, pipeId, imgGray, params, bank, markers, std::cerr, outFileName.str());
#else
      detection(frameId, pipeId, imgGray, params, bank, markers, outputFile, outFileName.str());
#endif

      // if the original image is b/w convert it to BGRA so we can draw colors
      if(frame.channels() == 1)
        cv::cvtColor(imgGray, frame, cv::COLOR_GRAY2BGRA);

      drawMarkers(markers, frame);
      cv::imshow(windowName, frame);
      if( cv::waitKey(delay) == 27 ) break;
      char key = (char) cv::waitKey(delay);
      // stop capturing by pressing ESC
      if(key == 27)
        break;
      if(key == 'l' || key == 'L')
        delay = 10;
      // delay = 0 will wait for a key to be pressed
      if(key == 'd' || key == 'D')
        delay = 0;

      ++frameId;
    }

  }
  else if(bfs::is_directory(myPath))
  {
    CCTAG_COUT("*** Image sequence mode ***");

    std::vector<bfs::path> vFileInFolder;

    std::copy(bfs::directory_iterator(myPath), bfs::directory_iterator(), std::back_inserter(vFileInFolder)); // is directory_entry, which is
    std::sort(vFileInFolder.begin(), vFileInFolder.end());

    std::size_t frameId = 0;

    std::map<int, bfs::path> files[2];
    for(const auto & fileInFolder : vFileInFolder)
    {
      files[frameId & 1].insert(std::pair<int, bfs::path>(frameId, fileInFolder));
      frameId++;
    }

    tbb::parallel_for(0, 2, [&](size_t fileListIdx)
    {
      for(const auto & fileInFolder : files[fileListIdx])
      {
        const std::string subExt(bfs::extension(fileInFolder.second));

        if((subExt == ".png") || (subExt == ".jpg") || (subExt == ".PNG") || (subExt == ".JPG"))
        {

          std::cerr << "Processing image " << fileInFolder.second.string() << std::endl;

          cv::Mat src;
          src = cv::imread(fileInFolder.second.string());

          cv::Mat imgGray;
          cv::cvtColor(src, imgGray, CV_BGR2GRAY);

          // Call the CCTag detection
          int pipeId = (fileInFolder.first & 1);
          boost::ptr_list<CCTag> markers;
#ifdef PRINT_TO_CERR
          detection(fileInFolder.first, pipeId, imgGray, params, bank, markers, std::cerr, fileInFolder.second.stem().string());
#else
          detection(fileInFolder.first, pipeId, imgGray, params, bank, markers, outputFile, fileInFolder.second.stem().string());
#endif
          std::cerr << "Done processing image " << fileInFolder.second.string() << std::endl;
        }
      }
    });
  }
  else
  {
    throw std::logic_error("Unrecognized input.");
  }
  outputFile.close();
  return EXIT_SUCCESS;
}

<|endoftext|>