<commit_before>#include "Process.hpp"
#include "log.hpp"
#include "Filesystem.hpp"

#include <boost/algorithm/string/join.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

#include <cassert>
#include <stdexcept>

#include <sys/wait.h>
#include <unistd.h>

#if defined(__APPLE__) && defined(__DYNAMIC__)
#include <crt_externs.h>
#endif

namespace io = boost::iostreams;

namespace configure {

	namespace {

		char** get_environ()
		{
#if defined(__APPLE__) && defined(__DYNAMIC__)
			return *_NSGetEnviron();
#else
			return environ;
#endif
		}

		struct Pipe
		{
		private:
			io::file_descriptor_source _source;
			io::file_descriptor_sink _sink;

		public:
			Pipe()
			{
				int fds[2];
				if (::pipe(fds) == -1)
					throw std::runtime_error("pipe error");
				_source = io::file_descriptor_source(fds[0], io::file_descriptor_flags::close_handle);
				_sink = io::file_descriptor_sink(fds[1], io::file_descriptor_flags::close_handle);
			}

		public:
			io::file_descriptor_sink& sink() { return _sink; }
			io::file_descriptor_source& source() { return _source; }

		public:
			void close()
			{
				_sink.close();
				_source.close();
			}
		};

	} // !anonymous

	struct Process::Impl
	{
		Command const command;
		Options const options;
		boost::optional<ExitCode> exit_code;
		io::file_descriptor_source stdout_source;
		pid_t child;

		Impl(Command cmd, Options options)
			: command(_prepare_command(std::move(cmd)))
			, options(std::move(options))
			, exit_code(boost::none)
			, child(_create_child())
		{}

		pid_t _create_child()
		{
			char** env = nullptr;
			// Working directory
			if (this->options.working_directory)
			{
				throw "not there";
			}

			if (this->options.inherit_env)
			{
				env = get_environ();
			}

			std::unique_ptr<Pipe> stdin_pipe;
			std::unique_ptr<Pipe> stdout_pipe;
			std::unique_ptr<Pipe> stderr_pipe;
			std::tuple<bool, Stream, std::unique_ptr<Pipe>&, int> channels[] = {
				std::make_tuple(false,
				                this->options.stdin_,
				                std::ref(stdin_pipe),
				                STDIN_FILENO),
				std::make_tuple(true,
				                this->options.stdout_,
				                std::ref(stdout_pipe),
				                STDOUT_FILENO),
				std::make_tuple(true,
				                this->options.stderr_,
				                std::ref(stderr_pipe),
				                STDERR_FILENO),
			};

			for (auto& channel: channels)
				if (std::get<1>(channel) == Stream::PIPE)
					std::get<2>(channel).reset(new Pipe);

			log::debug("Spawning process:", boost::join(this->command, " "));
			pid_t child = ::fork();
			if (child < 0)
			{
				throw std::runtime_error("fork()");
			}
			else if (child == 0) // Child
			{
				for (auto& channel: channels)
				{
					Stream kind = std::get<1>(channel);
					bool is_sink = std::get<0>(channel);
					int old_fd = std::get<3>(channel);
					if (kind == Stream::PIPE)
					{
						int new_fd = (is_sink ?
						              std::get<2>(channel)->sink().handle() :
						              std::get<2>(channel)->source().handle());
					retry_dup2:
						int ret = ::dup2(new_fd, old_fd);
						if (ret == -1) {
							if (errno == EINTR) goto retry_dup2;
							::exit(EXIT_FAILURE);
						}
					}
					else if (kind == Stream::DEVNULL)
					{
						::close(old_fd);
					}
				}
				stdin_pipe.reset();
				stdout_pipe.reset();
				stderr_pipe.reset();
				std::vector<char const*> args;
				for (auto& arg: this->command)
					args.push_back(arg.c_str());
				args.push_back(nullptr);
				::execve(args[0], (char**) &args[0], env);
				::exit(EXIT_FAILURE);
			}
			else // Parent
			{
				if (this->options.stdout_ == Stream::PIPE)
					this->stdout_source = stdout_pipe->source();
			}
			return child;
		}

		Command _prepare_command(Command cmd)
		{
			cmd[0] = Filesystem::which(cmd[0]).get().string();
			return std::move(cmd);
		}

	};

	Process::Process(Command cmd, Options options)
		: _this(new Impl(std::move(cmd), std::move(options)))
	{}

	Process::~Process()
	{ this->wait(); }

	Process::Options const& Process::options() const
	{ return _this->options; }

	boost::optional<Process::ExitCode> Process::exit_code()
	{
		if (!_this->exit_code)
		{
			pid_t ret;
			int status;
			do
			{
				log::debug("Checking exit status of child", _this->child);
				ret = ::waitpid(_this->child, &status, WNOHANG);
			} while (ret == -1 && errno == EINTR);
			if (ret == -1)
				throw std::runtime_error("Waitpid failed");
			if (ret != 0)
			{
				log::debug("The child", _this->child,
				           "exited with status code", WEXITSTATUS(status));
				_this->exit_code = WEXITSTATUS(status);
			}
			else
				log::debug("The child", _this->child, "is still alive");
		}
		return _this->exit_code;
	}

	Process::ExitCode Process::wait()
	{
		while (!this->exit_code())
			log::debug("Waiting for child", _this->child, "to terminate");
		return _this->exit_code.get();
	}

	Process::ExitCode Process::call(Command cmd, Options options)
	{
		Process p(std::move(cmd), std::move(options));
		return p.wait();
	}

	std::string Process::check_output(Command cmd, Options options)
	{
		options.stdout_ = Stream::PIPE;
		options.stderr_ = Stream::DEVNULL;
		Process p(std::move(cmd), std::move(options));

		char buf[4096];
		std::string res;
		ssize_t size;
		auto& src = p._this->stdout_source;
		while (true)
		{
			size = ::read(src.handle(), buf, sizeof(buf));
			log::debug("Read from", p._this->child, "returned", size);
			if (size < 0)
			{
				if (errno == EINTR)
				{
					log::debug("Read interrupted by a signal, let's retry");
					continue;
				}
				throw std::runtime_error("read(): " + std::string(strerror(errno)));
			}
			if (size > 0)
			{
				log::debug("read", size, "bytes from child", p._this->child, "stdout");
				res.append(buf, size);
			}
			if (size == 0)
				break;
		}
		if (p.wait() != 0)
			throw std::runtime_error("Program failed");
		return res;
	}
}
<commit_msg>First shot a windows process compat.<commit_after>#include "Process.hpp"
#include "log.hpp"
#include "Filesystem.hpp"

#include <boost/config.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

#include <cassert>
#include <stdexcept>

#if defined(BOOST_POSIX_API)
# include <sys/wait.h>
# include <unistd.h>
# if defined(__APPLE__) && defined(__DYNAMIC__)
#  include <crt_externs.h> // For _NSGetEnviron()
# endif
#elif defined(BOOST_WINDOWS_API)
# include <Windows.h>
#else
# error "Unsupported platform"
#endif

namespace io = boost::iostreams;

namespace configure {

	namespace {

		char** get_environ()
		{
#if defined(__APPLE__) && defined(__DYNAMIC__)
			return *_NSGetEnviron();
#else
			return environ;
#endif
		}

#ifdef BOOST_WINDOWS_API
		typedef HANDLE file_descriptor_t;
#else
		typedef int file_descriptor_t;
#endif

		struct Pipe
		{
		private:
			io::file_descriptor_source _source;
			io::file_descriptor_sink _sink;

		public:
			Pipe()
			{
				file_descriptor_t fds[2];
#ifdef BOOST_WINDOWS_API
				if (!::CreatePipe(&fds[0], &fds[1], NULL, 0))
#else
				if (::pipe(fds) == -1)
#endif
					throw std::runtime_error("pipe error");
				_source = io::file_descriptor_source(
				  fds[0], io::file_descriptor_flags::close_handle);
				_sink = io::file_descriptor_sink(
				  fds[1], io::file_descriptor_flags::close_handle);
			}

		public:
			io::file_descriptor_sink& sink() { return _sink; }
			io::file_descriptor_source& source() { return _source; }

		public:
			void close()
			{
				_sink.close();
				_source.close();
			}
		};

#ifdef BOOST_WINDOWS_API
		struct Child
		{
		private:
			PROCESS_INFORMATION _proc_info;

		public:
			explicit Child(PROCESS_INFORMATION const& proc_info)
			    : _proc_info(proc_info)
			{}

			Child(Child&& other)
				: _proc_info(other._proc_info)
			{
				other._proc_info.hProcess = INVALID_HANDLE_VALUE;
				other._proc_info.hThread = INVALID_HANDLE_VALUE;
			}

			~Child()
			{
				::CloseHandle(proc_info.hProcess);
				::CloseHandle(proc_info.hThread);
			}

			HANDLE process_handle() const { return proc_info.hProcess; }
		};
#else
		struct Child
		{
		private:
			pid_t _pid;

		public:
			explicit Child(pid_t pid) : _pid(pid) {}
			pid_t process_handle() const { return _pid; }
		};
#endif

		std::ostream& operator <<(std::ostream& out, Child const& child)
		{
			return out << "<Process " << child.process_handle() << ">";
		}

	} // !anonymous

	struct Process::Impl
	{
		Command const command;
		Options const options;
		boost::optional<ExitCode> exit_code;
		io::file_descriptor_sink stdin_sink;
		io::file_descriptor_source stdout_source;
		io::file_descriptor_source stderr_source;
		Child child;

		Impl(Command cmd, Options options)
			: command(_prepare_command(std::move(cmd)))
			, options(std::move(options))
			, exit_code(boost::none)
			, child(_create_child())
		{}

#ifdef BOOST_POSIX_API
		pid_t _create_child()
		{
			char** env = nullptr;
			// Working directory
			if (this->options.working_directory)
			{
				throw "not there";
			}

			if (this->options.inherit_env)
			{
				env = get_environ();
			}

			std::unique_ptr<Pipe> stdin_pipe;
			std::unique_ptr<Pipe> stdout_pipe;
			std::unique_ptr<Pipe> stderr_pipe;
			std::tuple<bool, Stream, std::unique_ptr<Pipe>&, int> channels[] = {
				std::make_tuple(false,
				                this->options.stdin_,
				                std::ref(stdin_pipe),
				                STDIN_FILENO),
				std::make_tuple(true,
				                this->options.stdout_,
				                std::ref(stdout_pipe),
				                STDOUT_FILENO),
				std::make_tuple(true,
				                this->options.stderr_,
				                std::ref(stderr_pipe),
				                STDERR_FILENO),
			};

			for (auto& channel: channels)
				if (std::get<1>(channel) == Stream::PIPE)
					std::get<2>(channel).reset(new Pipe);

			log::debug("Spawning process:", boost::join(this->command, " "));
			pid_t child = ::fork();
			if (child < 0)
			{
				throw std::runtime_error("fork()");
			}
			else if (child == 0) // Child
			{
				for (auto& channel: channels)
				{
					Stream kind = std::get<1>(channel);
					bool is_sink = std::get<0>(channel);
					int old_fd = std::get<3>(channel);
					if (kind == Stream::PIPE)
					{
						int new_fd = (is_sink ?
						              std::get<2>(channel)->sink().handle() :
						              std::get<2>(channel)->source().handle());
					retry_dup2:
						int ret = ::dup2(new_fd, old_fd);
						if (ret == -1) {
							if (errno == EINTR) goto retry_dup2;
							::exit(EXIT_FAILURE);
						}
					}
					else if (kind == Stream::DEVNULL)
					{
						::close(old_fd);
					}
				}
				stdin_pipe.reset();
				stdout_pipe.reset();
				stderr_pipe.reset();
				std::vector<char const*> args;
				for (auto& arg: this->command)
					args.push_back(arg.c_str());
				args.push_back(nullptr);
				::execve(args[0], (char**) &args[0], env);
				::exit(EXIT_FAILURE);
			}
			else // Parent
			{
				if (this->options.stdin_ == Stream::PIPE)
					this->stdin_sink = stdin_pipe->sink();
				if (this->options.stdout_ == Stream::PIPE)
					this->stdout_source = stdout_pipe->source();
				if (this->options.stderr_ == Stream::PIPE)
					this->stderr_source = stderr_pipe->source();
			}
			return child;
		}
#elif defined(BOOST_WINDOWS_API)
		PROCESS_INFORMATION _create_child()
		{
			LPCTSTR exe = cmd[0].c_str();
			LPTSTR cmd_line;
			LPSECURITY_ATTRIBUTES proc_attrs = 0
			LPSECURITY_ATTRIBUTES thread_attrs = 0;
			BOOL inherit_handles = false;
			LPVOID env = nullptr;
			LPCTSTR work_dir = nullptr;
#if (_WIN32_WINNT >= 0x0600)
			DWORD creation_flags = EXTENDED_STARTUPINFO_PRESENT;
			STARTUPINFOEX startup_info_ex;
			ZeroMemory(&startup_info_ex, sizeof(STARTUPINFOEX));
			STARTUPINFO& startup_info = startup_info_ex.StartupInfo;
			startup_info.cb = sizeof(STARTUPINFOEX);
#else
			DWORD creation_flags = 0;
			STARTUPINFO startup_info;
			ZeroMemory(&startup_info, sizeof(STARTUPINFO));
			startup_info.cb = sizeof(STARTUPINFO);
#endif

			std::unique_ptr<Pipe> stdin_pipe;
			if (this->options.stdin_ == Stream::PIPE)
			{
				stdin_pipe.reset(new Pipe);
				::SetHandleInformation(stdin_pipe->source().handle(),
				                       HANDLE_FLAG_INHERIT,
				                       HANDLE_FLAG_INHERIT);
				startup_info.hStdInput = stdin_pipe->source().handle();
				startup_info.dwFlags |= STARTF_USESTDHANDLES;
				inherit_handles = true;
				this->stdin_sink = stdin_pipe->sink();
			}
			else if (this->options.stdin_ == Stream::DEVNULL)
			{
				startup_info.hStdInput = INVALID_HANDLE_VALUE;
				startup_info.dwFlags |= STARTF_USESTDHANDLES;
			}

			std::unique_ptr<Pipe> stdout_pipe;
			if (this->options.stdout_ == Stream::PIPE)
			{
				stdout_pipe.reset(new Pipe);
				::SetHandleInformation(stdout_pipe->sink().handle(),
				                       HANDLE_FLAG_INHERIT,
				                       HANDLE_FLAG_INHERIT);
				startup_info.hStdOutput = stdout_pipe->sink().handle();
				startup_info.dwFlags |= STARTF_USESTDHANDLES;
				inherit_handles = true;
				this->stdout_source = stdout_pipe->source();
			}
			else if (this->options.stdout_ == Stream::DEVNULL)
			{
				startup_info.hStdOutput = INVALID_HANDLE_VALUE;
				startup_info.dwFlags |= STARTF_USESTDHANDLES;
			}

			std::unique_ptr<Pipe> stderr_pipe;
			if (this->options.stderr_ == Stream::PIPE)
			{
				stderr_pipe.reset(new Pipe);
				::SetHandleInformation(stderr_pipe->sink().handle(),
				                       HANDLE_FLAG_INHERIT,
				                       HANDLE_FLAG_INHERIT);
				startup_info.hStdError = stderr_pipe->sink().handle();
				startup_info.dwFlags |= STARTF_USESTDHANDLES;
				inherit_handles = true;
				this->stderr_source = stderr_pipe->source();
			}
			else if (this->options.stderr_ == Stream::DEVNULL)
			{
				startup_info.hStdError = INVALID_HANDLE_VALUE;
				startup_info.dwFlags |= STARTF_USESTDHANDLES;
			}

			PROCESS_INFORMATION proc_info;
			auto ret = ::CreateProcess(
			  cmd[0].c_str(), quote<CommandParser::windows_shell>(cmd).c_str(),
			  proc_attrs, thread_attrs, inherit_handles, creation_flags, env,
			  work_dir, &startup_info, &proc_info);
			if (!ret)
				throw std::runtime_error("CreateProcess() error");
			return Child(proc_info);
		}
#endif // !BOOST_WINDOWS_API

		Command _prepare_command(Command cmd)
		{
			cmd[0] = Filesystem::which(cmd[0]).get().string();
			return std::move(cmd);
		}

	};

	Process::Process(Command cmd, Options options)
		: _this(new Impl(std::move(cmd), std::move(options)))
	{}

	Process::~Process()
	{ this->wait(); }

	Process::Options const& Process::options() const
	{ return _this->options; }

	boost::optional<Process::ExitCode> Process::exit_code()
	{
		if (!_this->exit_code)
		{
#ifdef BOOST_WINDOWS_API
			int ret = ::WaitForSingleObject(_this->child.process_handle(), 0);
			switch (ret)
			{
			case WAIT_FAILED:
				throw std::runtime_error("WaitForSingleObject() failed");
			case WAIT_ABANDONED:
				log::warning(
				  "Wait on child", _this->child, "has been abandoned");
				break;
			case WAIT_TIMEOUT:
				log::debug("The child", _this->child, "is still alive");
				break;
			case WAIT_OBJECT_0:
			{
				DWORD exit_code;
				if (!::GetExitCodeProcess(
				      _this->child.process_handle(), &exit_code))
					throw std::runtime_error("GetExitCodeProcess() failed");
				log::debug("The child", _this->child,
				           "exited with status code", exit_code);
				_this->exit_code = exit_code;
			}
			}
#else
			pid_t ret;
			int status;
			do
			{
				log::debug("Checking exit status of child", _this->child);
				ret =
				  ::waitpid(_this->child.process_handle(), &status, WNOHANG);
			} while (ret == -1 && errno == EINTR);
			if (ret == -1)
				throw std::runtime_error("Waitpid failed");
			if (ret != 0)
			{
				log::debug("The child", _this->child,
				           "exited with status code", WEXITSTATUS(status));
				_this->exit_code = WEXITSTATUS(status);
			}
			else
				log::debug("The child", _this->child, "is still alive");
#endif
		}
		return _this->exit_code;
	}

	Process::ExitCode Process::wait()
	{
		while (!this->exit_code())
			log::debug("Waiting for child", _this->child, "to terminate");
		return _this->exit_code.get();
	}

	Process::ExitCode Process::call(Command cmd, Options options)
	{
		Process p(std::move(cmd), std::move(options));
		return p.wait();
	}

	std::string Process::check_output(Command cmd, Options options)
	{
		options.stdout_ = Stream::PIPE;
		options.stderr_ = Stream::DEVNULL;
		Process p(std::move(cmd), std::move(options));

		char buf[4096];
		std::string res;
		ssize_t size;
		auto& src = p._this->stdout_source;
		while (true)
		{
			size = ::read(src.handle(), buf, sizeof(buf));
			log::debug("Read from", p._this->child, "returned", size);
			if (size < 0)
			{
				if (errno == EINTR)
				{
					log::debug("Read interrupted by a signal, let's retry");
					continue;
				}
				throw std::runtime_error("read(): " + std::string(strerror(errno)));
			}
			if (size > 0)
			{
				log::debug("read", size, "bytes from child", p._this->child, "stdout");
				res.append(buf, size);
			}
			if (size == 0)
				break;
		}
		if (p.wait() != 0)
			throw std::runtime_error("Program failed");
		return res;
	}
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (ivan.frade@nokia.com)
**
** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at ivan.frade@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

// #include "qsparql_tracker.h"
#include "qsparql_tracker_p.h"

#include <qsparqlerror.h>
#include <qsparqlbinding.h>
#include <qsparqlquery.h>
#include <qsparqlqueryoptions.h>
#include <qsparqlresultrow.h>

#include <qcoreapplication.h>
#include <qvariant.h>
#include <qstringlist.h>
#include <qvector.h>
#include <qstring.h>
#include <qregexp.h>

#include <qdebug.h>

Q_DECLARE_METATYPE(QVector<QStringList>)

/*
    Allows a metatype to be declared for a type containing commas.
    For example:
	Q_DECLARE_METATYPE_COMMA(QList<QPair<QByteArray,QByteArray> >)
*/
#define Q_DECLARE_METATYPE_COMMA(...)                                   \
    QT_BEGIN_NAMESPACE                                                  \
    template <>                                                         \
    struct QMetaTypeId< __VA_ARGS__ >                                   \
    {                                                                   \
        enum { Defined = 1 };                                           \
        static int qt_metatype_id()                                     \
        {                                                               \
            static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
            if (!metatype_id)                                           \
                metatype_id = qRegisterMetaType< __VA_ARGS__ >( #__VA_ARGS__, \
                              reinterpret_cast< __VA_ARGS__ *>(quintptr(-1))); \
            return metatype_id;                                         \
        }                                                               \
    };                                                                  \
    QT_END_NAMESPACE

Q_DECLARE_METATYPE_COMMA(QMap<QString, QString>)
Q_DECLARE_METATYPE_COMMA(QVector<QMap<QString, QString> >)
Q_DECLARE_METATYPE_COMMA(QVector<QVector<QMap<QString, QString> > >)

class QTrackerDriver;

QT_BEGIN_NAMESPACE

// This enum is defined in tracker-sparql.h, but copy it here for now
// to avoid a dependency on that header.
typedef enum  {
    TRACKER_SPARQL_ERROR_PARSE,
    TRACKER_SPARQL_ERROR_UNKNOWN_CLASS,
    TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
    TRACKER_SPARQL_ERROR_TYPE,
    TRACKER_SPARQL_ERROR_CONSTRAINT,
    TRACKER_SPARQL_ERROR_NO_SPACE,
    TRACKER_SPARQL_ERROR_INTERNAL,
    TRACKER_SPARQL_ERROR_UNSUPPORTED
} TrackerSparqlError;

class QTrackerDriverPrivate {
public:
    QTrackerDriverPrivate();
    ~QTrackerDriverPrivate();
    QDBusInterface* iface;
    bool doBatch; // true: call BatchSparqlUpdate on Tracker instead of
                  // SparqlUpdateBlank
};

class QTrackerResultPrivate : public QObject {
    Q_OBJECT
public:
    QTrackerResultPrivate(QTrackerResult* res,
                          QSparqlQuery::StatementType tp);

    ~QTrackerResultPrivate();
    QDBusPendingCallWatcher* watcher;
    QVector<QStringList> data;
    QSparqlQuery::StatementType type;
    void setCall(QDBusPendingCall& call);
    static TrackerSparqlError errorNameToCode(const QString& name);
    static QSparqlError::ErrorType errorCodeToType(TrackerSparqlError code);

private Q_SLOTS:
    void onDBusCallFinished();
private:
    QTrackerResult* q; // public part
};

namespace {

// How to recognize tracker
QLatin1String service("org.freedesktop.Tracker1");
QLatin1String basePath("/org/freedesktop/Tracker1");
QLatin1String resourcesInterface("org.freedesktop.Tracker1.Resources");
QLatin1String resourcesPath("/org/freedesktop/Tracker1/Resources");

} // end of unnamed namespace

QTrackerResultPrivate::QTrackerResultPrivate(QTrackerResult* res,
                                             QSparqlQuery::StatementType tp)
: watcher(0), type(tp), q(res)
{
}

void QTrackerResultPrivate::setCall(QDBusPendingCall& call)
{
    // This function should be called only once
    watcher = new QDBusPendingCallWatcher(call);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
            this, SLOT(onDBusCallFinished()));
}

QTrackerResultPrivate::~QTrackerResultPrivate()
{
    delete watcher;
}

TrackerSparqlError QTrackerResultPrivate::errorNameToCode(const QString& name)
{
    if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Parse")) {
        return TRACKER_SPARQL_ERROR_PARSE;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.UnknownClass")) {
        return TRACKER_SPARQL_ERROR_UNKNOWN_CLASS;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.UnknownProperty")) {
        return TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Type")) {
        return TRACKER_SPARQL_ERROR_TYPE;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Constraint")) {
        return TRACKER_SPARQL_ERROR_CONSTRAINT;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.NoSpace")) {
        return TRACKER_SPARQL_ERROR_NO_SPACE;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Internal")) {
        return TRACKER_SPARQL_ERROR_INTERNAL;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Unsupported")) {
        return TRACKER_SPARQL_ERROR_UNSUPPORTED;
    } else {
        return static_cast<TrackerSparqlError>(-1);
    }
}

QSparqlError::ErrorType QTrackerResultPrivate::errorCodeToType(TrackerSparqlError code)
{
    switch (code) {
    case TRACKER_SPARQL_ERROR_PARSE:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_UNKNOWN_CLASS:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_TYPE:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_CONSTRAINT:
        return QSparqlError::ConnectionError;
    case TRACKER_SPARQL_ERROR_NO_SPACE:
        return QSparqlError::BackendError;
    case TRACKER_SPARQL_ERROR_INTERNAL:
        return QSparqlError::BackendError;
    case TRACKER_SPARQL_ERROR_UNSUPPORTED:
        return QSparqlError::BackendError;
    default:
        return QSparqlError::BackendError;
    }
}

void QTrackerResultPrivate::onDBusCallFinished()
{
    if (watcher->isError()) {
        QSparqlError error(watcher->error().message());
        if (watcher->error().type() == QDBusError::Other) {
            TrackerSparqlError code = errorNameToCode(watcher->error().name());
            error.setNumber(code);
            error.setType(errorCodeToType(code));
        } else {
            // Error from D-Bus
            error.setNumber((int)watcher->error().type());
            error.setType(QSparqlError::ConnectionError);
        }

        q->setLastError(error);
        emit q->finished();
        qWarning() << "QTrackerResult:" << q->lastError() << q->query();
        return;
    }

    switch (type) {
    case QSparqlQuery::AskStatement:
    case QSparqlQuery::SelectStatement:
    {
        QDBusPendingReply<QVector<QStringList> > reply = *watcher;
        data = reply.argumentAt<0>();

        if (type == QSparqlQuery::AskStatement && data.count() == 1 && data[0].count() == 1)
        {
            QVariant boolValue = data[0][0];
            q->setBoolValue(boolValue.toBool());
        }

        emit q->dataReady(data.size());
        break;
    }
    default:
        // TODO: handle update results here
        break;
    }
    Q_EMIT q->finished();
}

QTrackerResult::QTrackerResult(QSparqlQuery::StatementType tp)
{
    d = new QTrackerResultPrivate(this, tp);
}

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

QTrackerResult* QTrackerDriver::exec(const QString& query,
                          QSparqlQuery::StatementType type,
                          const QSparqlQueryOptions& options)
{
    if (options.executionMethod() == QSparqlQueryOptions::SyncExec)
        return 0;

    QTrackerResult* res = new QTrackerResult(type);
    res->setQuery(query);

    QString funcToCall;
    switch (type) {
    case QSparqlQuery::AskStatement:
    case QSparqlQuery::SelectStatement:
    {
        funcToCall = QString::fromLatin1("SparqlQuery");
        break;
    }
    case QSparqlQuery::InsertStatement: // fall-through
    case QSparqlQuery::DeleteStatement:
    {
        if (d->doBatch || options.priority() == QSparqlQueryOptions::LowPriority) {
            funcToCall = QString::fromLatin1("BatchSparqlUpdate");
        }
        else {
            funcToCall = QString::fromLatin1("SparqlUpdateBlank");
        }
        break;
    }
    default:
        res->setLastError(QSparqlError(
                              QLatin1String("Non-supported statement type"),
                              QSparqlError::BackendError));
        qWarning() << "QTrackerResult:" << res->lastError() << res->query();
        return res;
        break;
    }
    QDBusPendingCall call = d->iface->asyncCall(funcToCall,
                                                QVariant(query));
    res->d->setCall(call);
    return res;
}

QSparqlBinding QTrackerResult::binding(int field) const
{
    if (!isValid()) {
        return QSparqlBinding();
    }

    int i = pos();
    if (field >= d->data[i].count() || field < 0) {
        qWarning() << "QTrackerResult::data: column" << field << "out of range";
        return QSparqlBinding();
    }

    QString name = QString::fromLatin1("$%1").arg(field + 1);
    return QSparqlBinding(name, QVariant(d->data[i][field]));
}

QVariant QTrackerResult::value(int field) const
{
    if (!isValid()) {
        return QVariant();
    }

    // The upper layer calls this function only when this Result is positioned
    // in a valid position, so we don't need to check that.
    int i = pos();
    if (field >= d->data[i].count() || field < 0) {
        qWarning() << "QTrackerResult::data: column" << field << "out of range";
        return QVariant();
    }
    return d->data[i][field];
}

void QTrackerResult::waitForFinished()
{
    if (d->watcher)
        d->watcher->waitForFinished();
}

bool QTrackerResult::isFinished() const
{
    if (d->watcher)
        return d->watcher->isFinished();
    return true;
}

int QTrackerResult::size() const
{
    return d->data.count();
}

QSparqlResultRow QTrackerResult::current() const
{
    if (!isValid()) {
        return QSparqlResultRow();
    }

    QSparqlResultRow info;
    if (pos() >= d->data.count() || pos() < 0)
        return info;

    QStringList resultStrings = d->data[pos()];
    Q_FOREACH (const QString& str, resultStrings) {
        // This only creates a binding with the values but with empty column
        // names.
        // TODO: how to add column names?
        QSparqlBinding b(QString(), str);
        info.append(b);
    }
    return info;
}

bool QTrackerResult::hasFeature(QSparqlResult::Feature feature) const
{
    switch (feature) {
        case QSparqlResult::Sync:
        case QSparqlResult::ForwardOnly:
            return false;
        case QSparqlResult::QuerySize:
            return true;
        default:
            return false;
    }
}

QTrackerDriverPrivate::QTrackerDriverPrivate()
    : iface(0),  doBatch(false)
{
}

QTrackerDriverPrivate::~QTrackerDriverPrivate()
{
    delete iface;
}

QTrackerDriver::QTrackerDriver(QObject* parent)
    : QSparqlDriver(parent)
{
    d = new QTrackerDriverPrivate();

    qRegisterMetaType<QVector<QStringList> >();
    qDBusRegisterMetaType<QVector<QStringList> >();

    qRegisterMetaType<QMap<QString, QString> >();
    qRegisterMetaType<QVector<QMap<QString, QString> > >();
    qDBusRegisterMetaType<QVector<QMap<QString, QString> > >();

    /*
    if(!trackerBus().interface()->isServiceRegistered(service_g)
        && (trackerBus().interface()->startService(service_g)
            , !trackerBus().interface()->isServiceRegistered(service_g)))
        qCritical() << "cannot connect to org.freedesktop.Tracker1 service";
    */
}

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

bool QTrackerDriver::hasFeature(QSparqlConnection::Feature f) const
{
    switch (f) {
    case QSparqlConnection::QuerySize:
    case QSparqlConnection::DefaultGraph:
    case QSparqlConnection::AskQueries:
    case QSparqlConnection::UpdateQueries:
    case QSparqlConnection::AsyncExec:
        return true;
    case QSparqlConnection::ConstructQueries:
    case QSparqlConnection::SyncExec:
        return false;
    default:
        return false;
    }
    return false;
}

bool QTrackerDriver::open(const QSparqlConnectionOptions& options)
{
    // This option has been removed from API documentation as it is replaced by
    // QSparqlQueryOption::LowPriority. The implemenation needs to be kept
    // for backward compatibility.
    QVariant batchOption = options.option(QString::fromLatin1("batch"));
    if (!batchOption.isNull()) {
        d->doBatch = batchOption.toBool();
    }

    if (isOpen())
        close();
    d->iface = new QDBusInterface(service, resourcesPath,
                                  resourcesInterface,
                                  QDBusConnection::sessionBus());

    setOpen(true);
    setOpenError(false);

    return true;
}

void QTrackerDriver::close()
{
    if (isOpen()) {
        delete d->iface;
        d->iface = 0;
        setOpen(false);
        setOpenError(false);
    }
}

QT_END_NAMESPACE

#include "qsparql_tracker.moc"
<commit_msg>Use Q_EMIT in tracker results<commit_after>/****************************************************************************
**
** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (ivan.frade@nokia.com)
**
** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at ivan.frade@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

// #include "qsparql_tracker.h"
#include "qsparql_tracker_p.h"

#include <qsparqlerror.h>
#include <qsparqlbinding.h>
#include <qsparqlquery.h>
#include <qsparqlqueryoptions.h>
#include <qsparqlresultrow.h>

#include <qcoreapplication.h>
#include <qvariant.h>
#include <qstringlist.h>
#include <qvector.h>
#include <qstring.h>
#include <qregexp.h>

#include <qdebug.h>

Q_DECLARE_METATYPE(QVector<QStringList>)

/*
    Allows a metatype to be declared for a type containing commas.
    For example:
	Q_DECLARE_METATYPE_COMMA(QList<QPair<QByteArray,QByteArray> >)
*/
#define Q_DECLARE_METATYPE_COMMA(...)                                   \
    QT_BEGIN_NAMESPACE                                                  \
    template <>                                                         \
    struct QMetaTypeId< __VA_ARGS__ >                                   \
    {                                                                   \
        enum { Defined = 1 };                                           \
        static int qt_metatype_id()                                     \
        {                                                               \
            static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
            if (!metatype_id)                                           \
                metatype_id = qRegisterMetaType< __VA_ARGS__ >( #__VA_ARGS__, \
                              reinterpret_cast< __VA_ARGS__ *>(quintptr(-1))); \
            return metatype_id;                                         \
        }                                                               \
    };                                                                  \
    QT_END_NAMESPACE

Q_DECLARE_METATYPE_COMMA(QMap<QString, QString>)
Q_DECLARE_METATYPE_COMMA(QVector<QMap<QString, QString> >)
Q_DECLARE_METATYPE_COMMA(QVector<QVector<QMap<QString, QString> > >)

class QTrackerDriver;

QT_BEGIN_NAMESPACE

// This enum is defined in tracker-sparql.h, but copy it here for now
// to avoid a dependency on that header.
typedef enum  {
    TRACKER_SPARQL_ERROR_PARSE,
    TRACKER_SPARQL_ERROR_UNKNOWN_CLASS,
    TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
    TRACKER_SPARQL_ERROR_TYPE,
    TRACKER_SPARQL_ERROR_CONSTRAINT,
    TRACKER_SPARQL_ERROR_NO_SPACE,
    TRACKER_SPARQL_ERROR_INTERNAL,
    TRACKER_SPARQL_ERROR_UNSUPPORTED
} TrackerSparqlError;

class QTrackerDriverPrivate {
public:
    QTrackerDriverPrivate();
    ~QTrackerDriverPrivate();
    QDBusInterface* iface;
    bool doBatch; // true: call BatchSparqlUpdate on Tracker instead of
                  // SparqlUpdateBlank
};

class QTrackerResultPrivate : public QObject {
    Q_OBJECT
public:
    QTrackerResultPrivate(QTrackerResult* res,
                          QSparqlQuery::StatementType tp);

    ~QTrackerResultPrivate();
    QDBusPendingCallWatcher* watcher;
    QVector<QStringList> data;
    QSparqlQuery::StatementType type;
    void setCall(QDBusPendingCall& call);
    static TrackerSparqlError errorNameToCode(const QString& name);
    static QSparqlError::ErrorType errorCodeToType(TrackerSparqlError code);

private Q_SLOTS:
    void onDBusCallFinished();
private:
    QTrackerResult* q; // public part
};

namespace {

// How to recognize tracker
QLatin1String service("org.freedesktop.Tracker1");
QLatin1String basePath("/org/freedesktop/Tracker1");
QLatin1String resourcesInterface("org.freedesktop.Tracker1.Resources");
QLatin1String resourcesPath("/org/freedesktop/Tracker1/Resources");

} // end of unnamed namespace

QTrackerResultPrivate::QTrackerResultPrivate(QTrackerResult* res,
                                             QSparqlQuery::StatementType tp)
: watcher(0), type(tp), q(res)
{
}

void QTrackerResultPrivate::setCall(QDBusPendingCall& call)
{
    // This function should be called only once
    watcher = new QDBusPendingCallWatcher(call);
    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
            this, SLOT(onDBusCallFinished()));
}

QTrackerResultPrivate::~QTrackerResultPrivate()
{
    delete watcher;
}

TrackerSparqlError QTrackerResultPrivate::errorNameToCode(const QString& name)
{
    if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Parse")) {
        return TRACKER_SPARQL_ERROR_PARSE;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.UnknownClass")) {
        return TRACKER_SPARQL_ERROR_UNKNOWN_CLASS;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.UnknownProperty")) {
        return TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Type")) {
        return TRACKER_SPARQL_ERROR_TYPE;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Constraint")) {
        return TRACKER_SPARQL_ERROR_CONSTRAINT;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.NoSpace")) {
        return TRACKER_SPARQL_ERROR_NO_SPACE;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Internal")) {
        return TRACKER_SPARQL_ERROR_INTERNAL;
    } else if (name == QLatin1String("org.freedesktop.Tracker1.SparqlError.Unsupported")) {
        return TRACKER_SPARQL_ERROR_UNSUPPORTED;
    } else {
        return static_cast<TrackerSparqlError>(-1);
    }
}

QSparqlError::ErrorType QTrackerResultPrivate::errorCodeToType(TrackerSparqlError code)
{
    switch (code) {
    case TRACKER_SPARQL_ERROR_PARSE:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_UNKNOWN_CLASS:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_TYPE:
        return QSparqlError::StatementError;
    case TRACKER_SPARQL_ERROR_CONSTRAINT:
        return QSparqlError::ConnectionError;
    case TRACKER_SPARQL_ERROR_NO_SPACE:
        return QSparqlError::BackendError;
    case TRACKER_SPARQL_ERROR_INTERNAL:
        return QSparqlError::BackendError;
    case TRACKER_SPARQL_ERROR_UNSUPPORTED:
        return QSparqlError::BackendError;
    default:
        return QSparqlError::BackendError;
    }
}

void QTrackerResultPrivate::onDBusCallFinished()
{
    if (watcher->isError()) {
        QSparqlError error(watcher->error().message());
        if (watcher->error().type() == QDBusError::Other) {
            TrackerSparqlError code = errorNameToCode(watcher->error().name());
            error.setNumber(code);
            error.setType(errorCodeToType(code));
        } else {
            // Error from D-Bus
            error.setNumber((int)watcher->error().type());
            error.setType(QSparqlError::ConnectionError);
        }

        q->setLastError(error);
        Q_EMIT q->finished();
        qWarning() << "QTrackerResult:" << q->lastError() << q->query();
        return;
    }

    switch (type) {
    case QSparqlQuery::AskStatement:
    case QSparqlQuery::SelectStatement:
    {
        QDBusPendingReply<QVector<QStringList> > reply = *watcher;
        data = reply.argumentAt<0>();

        if (type == QSparqlQuery::AskStatement && data.count() == 1 && data[0].count() == 1)
        {
            QVariant boolValue = data[0][0];
            q->setBoolValue(boolValue.toBool());
        }

        Q_EMIT q->dataReady(data.size());
        break;
    }
    default:
        // TODO: handle update results here
        break;
    }
    Q_EMIT q->finished();
}

QTrackerResult::QTrackerResult(QSparqlQuery::StatementType tp)
{
    d = new QTrackerResultPrivate(this, tp);
}

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

QTrackerResult* QTrackerDriver::exec(const QString& query,
                          QSparqlQuery::StatementType type,
                          const QSparqlQueryOptions& options)
{
    if (options.executionMethod() == QSparqlQueryOptions::SyncExec)
        return 0;

    QTrackerResult* res = new QTrackerResult(type);
    res->setQuery(query);

    QString funcToCall;
    switch (type) {
    case QSparqlQuery::AskStatement:
    case QSparqlQuery::SelectStatement:
    {
        funcToCall = QString::fromLatin1("SparqlQuery");
        break;
    }
    case QSparqlQuery::InsertStatement: // fall-through
    case QSparqlQuery::DeleteStatement:
    {
        if (d->doBatch || options.priority() == QSparqlQueryOptions::LowPriority) {
            funcToCall = QString::fromLatin1("BatchSparqlUpdate");
        }
        else {
            funcToCall = QString::fromLatin1("SparqlUpdateBlank");
        }
        break;
    }
    default:
        res->setLastError(QSparqlError(
                              QLatin1String("Non-supported statement type"),
                              QSparqlError::BackendError));
        qWarning() << "QTrackerResult:" << res->lastError() << res->query();
        return res;
        break;
    }
    QDBusPendingCall call = d->iface->asyncCall(funcToCall,
                                                QVariant(query));
    res->d->setCall(call);
    return res;
}

QSparqlBinding QTrackerResult::binding(int field) const
{
    if (!isValid()) {
        return QSparqlBinding();
    }

    int i = pos();
    if (field >= d->data[i].count() || field < 0) {
        qWarning() << "QTrackerResult::data: column" << field << "out of range";
        return QSparqlBinding();
    }

    QString name = QString::fromLatin1("$%1").arg(field + 1);
    return QSparqlBinding(name, QVariant(d->data[i][field]));
}

QVariant QTrackerResult::value(int field) const
{
    if (!isValid()) {
        return QVariant();
    }

    // The upper layer calls this function only when this Result is positioned
    // in a valid position, so we don't need to check that.
    int i = pos();
    if (field >= d->data[i].count() || field < 0) {
        qWarning() << "QTrackerResult::data: column" << field << "out of range";
        return QVariant();
    }
    return d->data[i][field];
}

void QTrackerResult::waitForFinished()
{
    if (d->watcher)
        d->watcher->waitForFinished();
}

bool QTrackerResult::isFinished() const
{
    if (d->watcher)
        return d->watcher->isFinished();
    return true;
}

int QTrackerResult::size() const
{
    return d->data.count();
}

QSparqlResultRow QTrackerResult::current() const
{
    if (!isValid()) {
        return QSparqlResultRow();
    }

    QSparqlResultRow info;
    if (pos() >= d->data.count() || pos() < 0)
        return info;

    QStringList resultStrings = d->data[pos()];
    Q_FOREACH (const QString& str, resultStrings) {
        // This only creates a binding with the values but with empty column
        // names.
        // TODO: how to add column names?
        QSparqlBinding b(QString(), str);
        info.append(b);
    }
    return info;
}

bool QTrackerResult::hasFeature(QSparqlResult::Feature feature) const
{
    switch (feature) {
        case QSparqlResult::Sync:
        case QSparqlResult::ForwardOnly:
            return false;
        case QSparqlResult::QuerySize:
            return true;
        default:
            return false;
    }
}

QTrackerDriverPrivate::QTrackerDriverPrivate()
    : iface(0),  doBatch(false)
{
}

QTrackerDriverPrivate::~QTrackerDriverPrivate()
{
    delete iface;
}

QTrackerDriver::QTrackerDriver(QObject* parent)
    : QSparqlDriver(parent)
{
    d = new QTrackerDriverPrivate();

    qRegisterMetaType<QVector<QStringList> >();
    qDBusRegisterMetaType<QVector<QStringList> >();

    qRegisterMetaType<QMap<QString, QString> >();
    qRegisterMetaType<QVector<QMap<QString, QString> > >();
    qDBusRegisterMetaType<QVector<QMap<QString, QString> > >();

    /*
    if(!trackerBus().interface()->isServiceRegistered(service_g)
        && (trackerBus().interface()->startService(service_g)
            , !trackerBus().interface()->isServiceRegistered(service_g)))
        qCritical() << "cannot connect to org.freedesktop.Tracker1 service";
    */
}

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

bool QTrackerDriver::hasFeature(QSparqlConnection::Feature f) const
{
    switch (f) {
    case QSparqlConnection::QuerySize:
    case QSparqlConnection::DefaultGraph:
    case QSparqlConnection::AskQueries:
    case QSparqlConnection::UpdateQueries:
    case QSparqlConnection::AsyncExec:
        return true;
    case QSparqlConnection::ConstructQueries:
    case QSparqlConnection::SyncExec:
        return false;
    default:
        return false;
    }
    return false;
}

bool QTrackerDriver::open(const QSparqlConnectionOptions& options)
{
    // This option has been removed from API documentation as it is replaced by
    // QSparqlQueryOption::LowPriority. The implemenation needs to be kept
    // for backward compatibility.
    QVariant batchOption = options.option(QString::fromLatin1("batch"));
    if (!batchOption.isNull()) {
        d->doBatch = batchOption.toBool();
    }

    if (isOpen())
        close();
    d->iface = new QDBusInterface(service, resourcesPath,
                                  resourcesInterface,
                                  QDBusConnection::sessionBus());

    setOpen(true);
    setOpenError(false);

    return true;
}

void QTrackerDriver::close()
{
    if (isOpen()) {
        delete d->iface;
        d->iface = 0;
        setOpen(false);
        setOpenError(false);
    }
}

QT_END_NAMESPACE

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


<commit_before>#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <C5G/C5G.h>
#include <C5G/Grasp.h>

namespace C5G{
  void C5G::moveCartesian(const Pose& p){
    std::cout << "Relative movement to (" << p.x << ", " << p.y << ", " << p.z << ")\nOrientation: (" << p.alpha << ", " << p.beta << ", " << p.gamma << "\n";
  }

  const Pose C5G::safePose={0.3, 0, 0.7, 0, 0, 0};
  void C5G::moveCartesianGlobal(const Pose& p){
    std::cout << "Global movement to (" << p.x << ", " << p.y << ", " << p.z << ")\nOrientation: (" << p.alpha << ", " << p.beta << ", " << p.gamma << "\n";
  }

  void C5G::init(){
    std::cout << "Initing the system..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(3));
    std::cout << "Done.\n";
  }

  void C5G::standby(){
    std::cout << "Goodbye, cruel world..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "I'm leaving you today..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "Goodbye..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "Goodbye..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "Goodbye.\n";
  }
  void C5G::setGripping(double strength){
    std::cout << "Closing the plier with strength " << strength << "\n";
    boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
  }
  void C5G::executeGrasp(const Grasp& g){
    moveCartesian(g.approach);
    moveCartesian(g.grasp);
    setGripping(g.force);
    moveCartesian(g.approach);
  }
}
<commit_msg>Whops C5G_dummy<commit_after>#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <C5G/C5G.h>
#include <C5G/Grasp.h>

namespace C5G{
  void C5G::moveCartesian(const Pose& p){
    std::cout << "Relative movement to (" << p.x << ", " << p.y << ", " << p.z << ")\nOrientation: (" << p.alpha << ", " << p.beta << ", " << p.gamma << "\n";
  }

  const Pose C5G::safePose={0.3, 0, 0.7, 0, 0, 0};
  void C5G::moveCartesianGlobal(const Pose& p){
    std::cout << "Global movement to (" << p.x << ", " << p.y << ", " << p.z << ")\nOrientation: (" << p.alpha << ", " << p.beta << ", " << p.gamma << "\n";
  }

  void C5G::init(const std::string& ip, const std::string& sysID){
    std::cout << "Initing the system..\nConnecting to IP address: " << ip << "\nSystem ID: " << sysID << "\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(3));
    std::cout << "Done.\n";
  }

  void C5G::standby(){
    std::cout << "Goodbye, cruel world..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "I'm leaving you today..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "Goodbye..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "Goodbye..\n";
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
    std::cout << "Goodbye.\n";
  }
  void C5G::setGripping(double strength){
    std::cout << "Closing the plier with strength " << strength << "\n";
    boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
  }
  void C5G::executeGrasp(const Grasp& g){
    moveCartesian(g.approach);
    moveCartesian(g.grasp);
    setGripping(g.force);
    moveCartesian(g.approach);
  }
  C5G::~C5G(){
    standby();
  }
}

<|endoftext|>


<commit_before>/************************************************************************
	filename: 	CEGUIRenderer.cpp
	created:	20/2/2004
	author:		Paul D Turner

	purpose:	Some base class implementation for Renderer objects
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://crayzedsgui.sourceforge.net)
    Copyright (C)2004 Paul D Turner (crayzed@users.sourceforge.net)

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIRenderer.h"
#include "CEGUIEventSet.h"
#include "CEGUIEvent.h"
#include "CEGUIDefaultResourceProvider.h"

// Start of CEGUI namespace section
namespace CEGUI
{

/*************************************************************************
	Event name constants (static data definitions)
*************************************************************************/
const utf8	Renderer::EventDisplaySizeChanged[]		= "DisplayModeChanged";

/*************************************************************************
	Implementation constants
*************************************************************************/
const float	Renderer::GuiZInitialValue		= 1.0f;
const float	Renderer::GuiZElementStep		= 0.001f;		// this is enough for 1000 Windows.
const float	Renderer::GuiZLayerStep			= 0.0001f;		// provides space for 10 layers per Window.

/*************************************************************************
	Constructor
*************************************************************************/
Renderer::Renderer(void)
{
	// setup standard events available
	addEvent(EventDisplaySizeChanged);

	// default initialisation
	resetZValue();
}

/*************************************************************************
	Destructor
*************************************************************************/
Renderer::~Renderer(void)
{
    if(d_resourceProvider)
    {
        delete d_resourceProvider;
        d_resourceProvider = 0;
    }
}

ResourceProvider* Renderer::createResourceProvider(void)
{
    d_resourceProvider = new DefaultResourceProvider();
    return d_resourceProvider;
}

} // End of  CEGUI namespace section
<commit_msg>Initialise d_resourceProvider.<commit_after>/************************************************************************
	filename: 	CEGUIRenderer.cpp
	created:	20/2/2004
	author:		Paul D Turner

	purpose:	Some base class implementation for Renderer objects
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://crayzedsgui.sourceforge.net)
    Copyright (C)2004 Paul D Turner (crayzed@users.sourceforge.net)

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIRenderer.h"
#include "CEGUIEventSet.h"
#include "CEGUIEvent.h"
#include "CEGUIDefaultResourceProvider.h"

// Start of CEGUI namespace section
namespace CEGUI
{

/*************************************************************************
	Event name constants (static data definitions)
*************************************************************************/
const utf8	Renderer::EventDisplaySizeChanged[]		= "DisplayModeChanged";

/*************************************************************************
	Implementation constants
*************************************************************************/
const float	Renderer::GuiZInitialValue		= 1.0f;
const float	Renderer::GuiZElementStep		= 0.001f;		// this is enough for 1000 Windows.
const float	Renderer::GuiZLayerStep			= 0.0001f;		// provides space for 10 layers per Window.

/*************************************************************************
	Constructor
*************************************************************************/
Renderer::Renderer(void)
    : d_resourceProvider(0)
{
	// setup standard events available
	addEvent(EventDisplaySizeChanged);

	// default initialisation
	resetZValue();
}

/*************************************************************************
	Destructor
*************************************************************************/
Renderer::~Renderer(void)
{
    if(d_resourceProvider)
    {
        delete d_resourceProvider;
        d_resourceProvider = 0;
    }
}

ResourceProvider* Renderer::createResourceProvider(void)
{
    d_resourceProvider = new DefaultResourceProvider();
    return d_resourceProvider;
}

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include <time.h>
#include "xsi_application.h"
#include "AlembicLicensing.h"

#include <string>
#include <sstream>

using namespace std;

#if defined( EXOCORTEX_RLM_ONLY )
	#include "RlmSingletonDeclarations.h"
#endif // EXOCORTEX_RLM_ONLY

int s_alembicLicense = -1;

int GetAlembicLicense() {
	static string pluginName(XSI::CString(PLUGIN_NAME).GetAsciiString());

	if( s_alembicLicense != ALEMBIC_NO_LICENSE ) {
		return s_alembicLicense;
	}

	bool isWriterLicense = XSI::Application().IsInteractive();

	bool isForceReader = ( getenv("EXOCORTEX_ALEMBIC_FORCE_READER") != NULL );
	bool isForceWriter = ( getenv("EXOCORTEX_ALEMBIC_FORCE_WRITER") != NULL );

	if( isForceReader && isForceWriter ) {
		ESS_LOG_ERROR( "Both environment variables EXOCORTEX_ALEMBIC_FORCE_READER and EXOCORTEX_ALEMBIC_FORCE_WRITER defined, these conflict" );
	}

	if( isWriterLicense ) {
		if( isForceReader ) {
			ESS_LOG_ERROR( "Environment variable EXOCORTEX_ALEMBIC_FORCE_READER defined, forcing usage of read-only license." );
			isWriterLicense = false;
		}
	}
	if( ! isWriterLicense ) {
		if( isForceWriter ) {
			ESS_LOG_ERROR( "Environment variable EXOCORTEX_ALEMBIC_FORCE_WRITER defined, forcing usage of write-capable license." );
			isWriterLicense = true;
		}
	}

	vector<RlmProductID> rlmProductIds;
	int pluginLicenseResult;

	if( isWriterLicense ) {
		RlmProductID pluginLicenseIds[] = ALEMBIC_WRITER_LICENSE_IDS;
		for( int i = 0; i < sizeof( pluginLicenseIds ) / sizeof( RlmProductID ); i ++ ) {
			rlmProductIds.push_back( pluginLicenseIds[i] );
		}
		pluginLicenseResult = ALEMBIC_WRITER_LICENSE;
	}
	else {
		RlmProductID pluginLicenseIds[] = ALEMBIC_READER_LICENSE_IDS;
		for( int i = 0; i < sizeof( pluginLicenseIds ) / sizeof( RlmProductID ); i ++ ) {
			rlmProductIds.push_back( pluginLicenseIds[i] );
		}
		pluginLicenseResult = ALEMBIC_READER_LICENSE;
	}

	Exocortex::RlmSingleton& rlmSingleton = Exocortex::RlmSingleton::getSingleton();
	if( rlmSingleton.checkoutLicense( "", pluginName, rlmProductIds ) ) {
		s_alembicLicense = pluginLicenseResult;
	}
	else {
		s_alembicLicense = ALEMBIC_DEMO_LICENSE;
	}

	return s_alembicLicense;
}

bool HasAlembicWriterLicense() {
	return ( GetAlembicLicense() == ALEMBIC_WRITER_LICENSE );
}

bool HasAlembicReaderLicense() {
	return ( GetAlembicLicense() == ALEMBIC_WRITER_LICENSE )||( GetAlembicLicense() == ALEMBIC_READER_LICENSE );
}

#ifdef EXOCORTEX_SERVICES

namespace Exocortex {
	void essOnDemandInitialization() {
		static string pluginName(XSI::CString(PLUGIN_NAME).GetAsciiString());

		essInitializeSoftimage( pluginName.c_str(), PLUGIN_MAJOR_VERSION, PLUGIN_MINOR_VERSION );
	}
}

#endif // EXOCORTEX_SERVICES

<commit_msg>fixed bug #29.<commit_after>#include <time.h>
#include "xsi_application.h"
#include "AlembicLicensing.h"

#include <string>
#include <sstream>

using namespace std;

#if defined( EXOCORTEX_RLM_ONLY )
	#include "RlmSingletonDeclarations.h"
#endif // EXOCORTEX_RLM_ONLY

int s_alembicLicense = -1;

int GetAlembicLicense() {
	static string pluginName(XSI::CString(PLUGIN_NAME).GetAsciiString());

	if( s_alembicLicense != ALEMBIC_NO_LICENSE ) {
		return s_alembicLicense;
	}

	bool isWriterLicense = XSI::Application().IsInteractive();

	bool isForceReader = ( getenv("EXOCORTEX_ALEMBIC_FORCE_READER") != NULL );
	bool isForceWriter = ( getenv("EXOCORTEX_ALEMBIC_FORCE_WRITER") != NULL );

	if( isForceReader && isForceWriter ) {
		ESS_LOG_ERROR( "Both environment variables EXOCORTEX_ALEMBIC_FORCE_READER and EXOCORTEX_ALEMBIC_FORCE_WRITER defined, these conflict" );
	}

	if( isWriterLicense ) {
		if( isForceReader ) {
			ESS_LOG_WARNING( "Environment variable EXOCORTEX_ALEMBIC_FORCE_READER defined, forcing usage of read-only license." );
			isWriterLicense = false;
		}
	}
	if( ! isWriterLicense ) {
		if( isForceWriter ) {
			ESS_LOG_WARNING( "Environment variable EXOCORTEX_ALEMBIC_FORCE_WRITER defined, forcing usage of write-capable license." );
			isWriterLicense = true;
		}
	}

	vector<RlmProductID> rlmProductIds;
	int pluginLicenseResult;

	if( isWriterLicense ) {
		RlmProductID pluginLicenseIds[] = ALEMBIC_WRITER_LICENSE_IDS;
		for( int i = 0; i < sizeof( pluginLicenseIds ) / sizeof( RlmProductID ); i ++ ) {
			rlmProductIds.push_back( pluginLicenseIds[i] );
		}
		pluginLicenseResult = ALEMBIC_WRITER_LICENSE;
	}
	else {
		RlmProductID pluginLicenseIds[] = ALEMBIC_READER_LICENSE_IDS;
		for( int i = 0; i < sizeof( pluginLicenseIds ) / sizeof( RlmProductID ); i ++ ) {
			rlmProductIds.push_back( pluginLicenseIds[i] );
		}
		pluginLicenseResult = ALEMBIC_READER_LICENSE;
	}

	Exocortex::RlmSingleton& rlmSingleton = Exocortex::RlmSingleton::getSingleton();
	if( rlmSingleton.checkoutLicense( "", pluginName, rlmProductIds ) ) {
		s_alembicLicense = pluginLicenseResult;
	}
	else {
		s_alembicLicense = ALEMBIC_DEMO_LICENSE;
	}

	return s_alembicLicense;
}

bool HasAlembicWriterLicense() {
	return ( GetAlembicLicense() == ALEMBIC_WRITER_LICENSE );
}

bool HasAlembicReaderLicense() {
	return ( GetAlembicLicense() == ALEMBIC_WRITER_LICENSE )||( GetAlembicLicense() == ALEMBIC_READER_LICENSE );
}

#ifdef EXOCORTEX_SERVICES

namespace Exocortex {
	void essOnDemandInitialization() {
		static string pluginName(XSI::CString(PLUGIN_NAME).GetAsciiString());

		essInitializeSoftimage( pluginName.c_str(), PLUGIN_MAJOR_VERSION, PLUGIN_MINOR_VERSION );
	}
}

#endif // EXOCORTEX_SERVICES

<|endoftext|>


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

#include "CaptureDevice.h"

#include "Error.h"

#include "logging.h"
#include "utils.h"
#include "serialization.h"

#include "CaptureDeviceImpl.h"

using namespace tcam;

CaptureDevice::CaptureDevice ()
    : impl(new CaptureDeviceImpl())
{}

CaptureDevice::CaptureDevice (const DeviceInfo& info)
    : impl(new CaptureDeviceImpl())
{
    impl->open_device(info);
}

CaptureDevice::~CaptureDevice ()
{}

bool CaptureDevice::load_configuration (const std::string& filename)
{
    return impl->load_configuration(filename);
}

bool CaptureDevice::save_configuration (const std::string& filename)
{
    return impl->save_configuration(filename);
}

bool CaptureDevice::is_device_open () const
{
    return impl->is_device_open ();
}

DeviceInfo CaptureDevice::get_device () const
{
    return impl->get_device();
}

std::vector<Property*> CaptureDevice::get_available_properties ()
{
    return impl->get_available_properties();
}

Property* CaptureDevice::get_property (TCAM_PROPERTY_ID id)
{
    auto properties = get_available_properties();

    for (auto& p :  properties)
    {
        if (p->get_ID() == id)
        {
            return p;
        }
    }
    return nullptr;
}

Property* CaptureDevice::get_property_by_name (const std::string& name)
{
    auto properties = get_available_properties();

    for (auto& p :  properties)
    {
        if (p->get_name().compare(name) == 0)
        {
            return p;
        }
    }
    return nullptr;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const int64_t& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_INTEGER)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const double& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_DOUBLE)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const bool& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_BOOLEAN)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const std::string& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_STRING)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

std::vector<VideoFormatDescription> CaptureDevice::get_available_video_formats () const
{
    return impl->get_available_video_formats();
}

bool CaptureDevice::set_video_format (const VideoFormat& new_format)
{
    return impl->set_video_format(new_format);
}

VideoFormat CaptureDevice::get_active_video_format () const
{
    return impl->get_active_video_format();
}

bool CaptureDevice::start_stream (std::shared_ptr<SinkInterface> sink)
{
    return impl->start_stream(sink);
}

bool CaptureDevice::stop_stream ()
{
    return impl->stop_stream();
}

std::shared_ptr<CaptureDevice> tcam::open_device (const std::string& serial)
{
    for (const auto& d : get_device_list())
    {
        if (d.get_serial().compare(serial) == 0)
        {
            try
            {
                return std::make_shared<CaptureDevice>(CaptureDevice(d));
            }
            catch (const std::exception& err)
            {
                // TODO: set up error
                tcam_log(TCAM_LOG_ERROR, "Could not open CaptureDevice. Exception:\"%s\"", err.what());
                return nullptr;
            }
        }
    }

    return nullptr;
}
<commit_msg>Add check if name is empty<commit_after>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CaptureDevice.h"

#include "Error.h"

#include "logging.h"
#include "utils.h"
#include "serialization.h"

#include "CaptureDeviceImpl.h"

using namespace tcam;

CaptureDevice::CaptureDevice ()
    : impl(new CaptureDeviceImpl())
{}

CaptureDevice::CaptureDevice (const DeviceInfo& info)
    : impl(new CaptureDeviceImpl())
{
    impl->open_device(info);
}

CaptureDevice::~CaptureDevice ()
{}

bool CaptureDevice::load_configuration (const std::string& filename)
{
    return impl->load_configuration(filename);
}

bool CaptureDevice::save_configuration (const std::string& filename)
{
    return impl->save_configuration(filename);
}

bool CaptureDevice::is_device_open () const
{
    return impl->is_device_open ();
}

DeviceInfo CaptureDevice::get_device () const
{
    return impl->get_device();
}

std::vector<Property*> CaptureDevice::get_available_properties ()
{
    return impl->get_available_properties();
}

Property* CaptureDevice::get_property (TCAM_PROPERTY_ID id)
{
    auto properties = get_available_properties();

    for (auto& p :  properties)
    {
        if (p->get_ID() == id)
        {
            return p;
        }
    }
    return nullptr;
}

Property* CaptureDevice::get_property_by_name (const std::string& name)
{
    if (name.empty())
    {
        return nullptr;
    }

    auto properties = get_available_properties();

    for (auto& p :  properties)
    {
        if (p->get_name().compare(name) == 0)
        {
            return p;
        }
    }
    return nullptr;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const int64_t& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_INTEGER)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const double& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_DOUBLE)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const bool& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_BOOLEAN)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

bool CaptureDevice::set_property (TCAM_PROPERTY_ID id, const std::string& value)
{
    auto vec = get_available_properties();

    for (const auto& v : vec)
    {
        if (id == v->get_ID())
        {
            if (v->get_type() == TCAM_PROPERTY_TYPE_STRING)
            {
                return v->set_value(value);
            }
        }
    }

    return false;
}

std::vector<VideoFormatDescription> CaptureDevice::get_available_video_formats () const
{
    return impl->get_available_video_formats();
}

bool CaptureDevice::set_video_format (const VideoFormat& new_format)
{
    return impl->set_video_format(new_format);
}

VideoFormat CaptureDevice::get_active_video_format () const
{
    return impl->get_active_video_format();
}

bool CaptureDevice::start_stream (std::shared_ptr<SinkInterface> sink)
{
    return impl->start_stream(sink);
}

bool CaptureDevice::stop_stream ()
{
    return impl->stop_stream();
}

std::shared_ptr<CaptureDevice> tcam::open_device (const std::string& serial)
{
    for (const auto& d : get_device_list())
    {
        if (d.get_serial().compare(serial) == 0)
        {
            try
            {
                return std::make_shared<CaptureDevice>(CaptureDevice(d));
            }
            catch (const std::exception& err)
            {
                // TODO: set up error
                tcam_log(TCAM_LOG_ERROR, "Could not open CaptureDevice. Exception:\"%s\"", err.what());
                return nullptr;
            }
        }
    }

    return nullptr;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006-2021  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia 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 (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "vectorrealtotensor.h"

using namespace std;

namespace essentia {
namespace streaming {

const char* VectorRealToTensor::name = "VectorRealToTensor";
const char* VectorRealToTensor::category = "Standard";
const char* VectorRealToTensor::description = DOC("This algorithm generates tensors "
"out of a stream of input frames. The 4 dimensions of the tensors stand for (batchSize, channels, patchSize, featureSize):\n"
"  - batchSize: Number of patches per tensor. If batchSize is set to 0 it will accumulate patches until the end of the stream is reached and then produce a single tensor. "
"Warning: This option may exhaust memory depending on the size of the stream.\n"
"  - channels: Number of channels per tensor. Currently, only single-channel tensors are supported. Otherwise, an exception is thrown.\n"
"  - patchSize: Number of timestamps (i.e., number of frames) per patch.\n"
"  - featureSize: Expected number of features (e.g., mel bands) of every input frame. This algorithm throws an exception if the size of any frame is different from featureSize.\n"
"Additionally, the patchHopSize and batchHopSize parameters provide control over the amount of overlap on those dimensions.");

void VectorRealToTensor::configure() {
  vector<int> shape = parameter("shape").toVectorInt();
  _patchHopSize = parameter("patchHopSize").toInt();
  _batchHopSize = parameter("batchHopSize").toInt();
  _lastPatchMode = parameter("lastPatchMode").toString();

  _shape.resize(shape.size());
  for (size_t i = 0; i < shape.size(); i++) {
    if (shape[i] == 0) {
    throw EssentiaException("VectorRealToTensor: All dimensions should have a non-zero size.");
    }

    _shape[i] = shape[i];
  }

  if (shape[1] != 1) {
    throw EssentiaException("VectorRealToTensor: Currently only single-channel tensors are supported.");
  }

  _timeStamps = shape[2];
  _frame.setAcquireSize(_timeStamps);

  if (shape[0] == -1) {
    _accumulate = true;
  }

  if (_batchHopSize == 0) {
    _batchHopSize = shape[0];
  }

  if (_patchHopSize == 0) {
    _patchHopSize = _timeStamps;
  }

  _acc.assign(0, vector<vector<Real> >(_shape[2], vector<Real>(_shape[3], 0.0)));
  _push = false;

  if (_patchHopSize > _timeStamps) {
    throw EssentiaException("VectorRealToTensor: `patchHopSize` has to be smaller that the number of timestamps");
  }

  if (shape[0] > 0) {
    if (_batchHopSize > shape[0]) {
      throw EssentiaException("VectorRealToTensor: `batchHopSize` has to be smaller than the batch size (shape[0])");
    }
  }

}

AlgorithmStatus VectorRealToTensor::process() {
  EXEC_DEBUG("process()");
  if (_timeStamps != _frame.acquireSize()) {
    _frame.setAcquireSize(_timeStamps);
  }
  if (_patchHopSize != _frame.releaseSize()) {
    _frame.setReleaseSize(_patchHopSize);
  }

  // Check if we have enough frames to add a patch.
  int available = _frame.available();
  bool addPatch = (available >= _timeStamps);

  // If we should stop just take the remaining frames.
  if (shouldStop() && (available < _timeStamps)) {
    _frame.setAcquireSize(available);
    _frame.setReleaseSize(available);

    // Push if there are remaining frames
    if (_lastPatchMode == "repeat" && available > 0) {
      addPatch = true;
      _push = true;

    // or if we have been accumulating.
    } else if (_accumulate && _acc.size() >= 1) {
      addPatch = true;
      _push = true;
    }
  }

  // Return if there is nothing to do.
  if ((!addPatch) && (!_push)) return NO_INPUT;

  if (_push) {
    _tensor.setAcquireSize(1);
    _tensor.setReleaseSize(1);

    // Don't get frames if we just want to push.
    if (!addPatch) {
      _frame.setAcquireSize(0);
      _frame.setReleaseSize(0);
    }

  // Don't get a tensor if we are just accumulating.
  } else {
    _tensor.setAcquireSize(0);
    _tensor.setReleaseSize(0);
  }

  AlgorithmStatus status = acquireData();
  EXEC_DEBUG("data acquired (in: " << _frame.acquireSize()
            << " - out: " << _tensor.acquireSize() << ")");

  if (status != OK) {
    return status;
  };

  AlgorithmStatus outStatus = NO_OUTPUT;

  // Frames accumulation step.
  if (addPatch) {
    const vector<vector<Real> >& frame = _frame.tokens();

    // Sanity check.
    for (size_t i = 0; i < frame.size(); i++) {
      if ((int)frame[i].size() != _shape[3]) {
        throw EssentiaException("VectorRealToTensor: Found input frame with size ", frame[i].size(),
                                " while the algorithm was configured to work with frames with size ", _shape[3]);
      }
    }

    // Add a regular patch.
    if ((int)frame.size() == _timeStamps) {
      _acc.push_back(frame);

    // If size does not match rather repeat frames or discard them.
    } else {
      if (_lastPatchMode == "repeat") {
        if (frame.size() == 0) {
          EXEC_DEBUG("VectorRealToTensor: 0 frames remaining.");

        } else {
          if (frame.size() < 10) {
            E_WARNING("VectorRealToTensor: Last patch produced by repeating the last " << frame.size() << " frames. May result in unreliable predictions.");
          }
          vector<vector<Real> > padded_frame = frame;

          for (int i = 0; i < _timeStamps; i++) {
            padded_frame.push_back(frame[i % frame.size()]);
          }

          EXEC_DEBUG("VectorRealToTensor: Repeating the remaining " << frame.size() << " frames to make one last patch.");
          _acc.push_back(padded_frame);
        }

      } else if (_lastPatchMode == "discard") {
        EXEC_DEBUG("VectorRealToTensor: Discarding last frames");

      } else {
        throw EssentiaException("VectorRealToTensor: Incomplete patch found "
                                "before reaching the end of the stream. This is not supposed to happen");
      }
    }
  }

  // We only push if when we have filled the whole batch
  // or if we have reached the end of the stream in
  // accumulate mode.
  if (_push) {
    vector<int> shape = _shape;
    int batchHopSize = _batchHopSize;

    // If we have been accumulating we have to get the
    // tensor's shape from the current status of the
    // accumulator.
    if (_accumulate) {
      shape[0] = _acc.size();
      batchHopSize = _acc.size();

      if (_acc.size() == 0) {
        throw EssentiaException("VectorRealToTensor: The stream has finished without enough frames to "
                                "produce a patch of the desired size. Consider setting the `lastPatchMode` "
                                "parameter to `repeat` in order to produce a batch.");
      }
    }

    Tensor<Real>& tensor = *(Tensor<Real> *)_tensor.getFirstToken();

    // Explicit convertion of std:vector to std::array<Eigen::Index> for Clang.
    std::array<Eigen::Index, TENSORRANK> shapeEigenIndex;
    std::copy_n(shape.begin(), TENSORRANK, shapeEigenIndex.begin());

    tensor.resize(shapeEigenIndex);

    for (int i = 0; i < shape[0]; i++) {      // Batch axis
      for (int j = 0; j < shape[2]; j++) {    // Time axis
        for (int k = 0; k < shape[3]; k++) {  // Freq axis
          tensor(i, 0, j, k) = _acc[i][j][k];
        }
      }
    }

    // Empty the accumulator.
    _acc.erase(_acc.begin(), _acc.begin() + batchHopSize);

    _push = false;
    outStatus = OK;
  }

  // Check if we should push in the next process().
  if (!_accumulate) {
    if ((int)_acc.size() >= _shape[0]) _push = true;
  }

  EXEC_DEBUG("releasing");
  releaseData();
  EXEC_DEBUG("released");
  return outStatus;
}

void VectorRealToTensor::reset() {
  _acc.assign(0, vector<vector<Real> >(_shape[1], vector<Real>(_shape[2], 0.0)));
  _push = false;
}

} // namespace streaming
} // namespace essentia
<commit_msg>Fix documentation<commit_after>/*
 * Copyright (C) 2006-2021  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia 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 (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "vectorrealtotensor.h"

using namespace std;

namespace essentia {
namespace streaming {

const char* VectorRealToTensor::name = "VectorRealToTensor";
const char* VectorRealToTensor::category = "Standard";
const char* VectorRealToTensor::description = DOC("This algorithm generates tensors "
"out of a stream of input frames. The 4 dimensions of the tensors stand for (batchSize, channels, patchSize, featureSize):\n"
"  - batchSize: Number of patches per tensor. If batchSize is set to -1 it will accumulate patches until the end of the stream is reached and then produce a single tensor. "
"Warning: This option may exhaust memory depending on the size of the stream.\n"
"  - channels: Number of channels per tensor. Currently, only single-channel tensors are supported. Otherwise, an exception is thrown.\n"
"  - patchSize: Number of timestamps (i.e., number of frames) per patch.\n"
"  - featureSize: Expected number of features (e.g., mel bands) of every input frame. This algorithm throws an exception if the size of any frame is different from featureSize.\n"
"Additionally, the patchHopSize and batchHopSize parameters provide control over the amount of overlap on those dimensions.");

void VectorRealToTensor::configure() {
  vector<int> shape = parameter("shape").toVectorInt();
  _patchHopSize = parameter("patchHopSize").toInt();
  _batchHopSize = parameter("batchHopSize").toInt();
  _lastPatchMode = parameter("lastPatchMode").toString();

  _shape.resize(shape.size());
  for (size_t i = 0; i < shape.size(); i++) {
    if (shape[i] == 0) {
    throw EssentiaException("VectorRealToTensor: All dimensions should have a non-zero size.");
    }

    _shape[i] = shape[i];
  }

  if (shape[1] != 1) {
    throw EssentiaException("VectorRealToTensor: Currently only single-channel tensors are supported.");
  }

  _timeStamps = shape[2];
  _frame.setAcquireSize(_timeStamps);

  if (shape[0] == -1) {
    _accumulate = true;
  }

  if (_batchHopSize == 0) {
    _batchHopSize = shape[0];
  }

  if (_patchHopSize == 0) {
    _patchHopSize = _timeStamps;
  }

  _acc.assign(0, vector<vector<Real> >(_shape[2], vector<Real>(_shape[3], 0.0)));
  _push = false;

  if (_patchHopSize > _timeStamps) {
    throw EssentiaException("VectorRealToTensor: `patchHopSize` has to be smaller that the number of timestamps");
  }

  if (shape[0] > 0) {
    if (_batchHopSize > shape[0]) {
      throw EssentiaException("VectorRealToTensor: `batchHopSize` has to be smaller than the batch size (shape[0])");
    }
  }

}

AlgorithmStatus VectorRealToTensor::process() {
  EXEC_DEBUG("process()");
  if (_timeStamps != _frame.acquireSize()) {
    _frame.setAcquireSize(_timeStamps);
  }
  if (_patchHopSize != _frame.releaseSize()) {
    _frame.setReleaseSize(_patchHopSize);
  }

  // Check if we have enough frames to add a patch.
  int available = _frame.available();
  bool addPatch = (available >= _timeStamps);

  // If we should stop just take the remaining frames.
  if (shouldStop() && (available < _timeStamps)) {
    _frame.setAcquireSize(available);
    _frame.setReleaseSize(available);

    // Push if there are remaining frames
    if (_lastPatchMode == "repeat" && available > 0) {
      addPatch = true;
      _push = true;

    // or if we have been accumulating.
    } else if (_accumulate && _acc.size() >= 1) {
      addPatch = true;
      _push = true;
    }
  }

  // Return if there is nothing to do.
  if ((!addPatch) && (!_push)) return NO_INPUT;

  if (_push) {
    _tensor.setAcquireSize(1);
    _tensor.setReleaseSize(1);

    // Don't get frames if we just want to push.
    if (!addPatch) {
      _frame.setAcquireSize(0);
      _frame.setReleaseSize(0);
    }

  // Don't get a tensor if we are just accumulating.
  } else {
    _tensor.setAcquireSize(0);
    _tensor.setReleaseSize(0);
  }

  AlgorithmStatus status = acquireData();
  EXEC_DEBUG("data acquired (in: " << _frame.acquireSize()
            << " - out: " << _tensor.acquireSize() << ")");

  if (status != OK) {
    return status;
  };

  AlgorithmStatus outStatus = NO_OUTPUT;

  // Frames accumulation step.
  if (addPatch) {
    const vector<vector<Real> >& frame = _frame.tokens();

    // Sanity check.
    for (size_t i = 0; i < frame.size(); i++) {
      if ((int)frame[i].size() != _shape[3]) {
        throw EssentiaException("VectorRealToTensor: Found input frame with size ", frame[i].size(),
                                " while the algorithm was configured to work with frames with size ", _shape[3]);
      }
    }

    // Add a regular patch.
    if ((int)frame.size() == _timeStamps) {
      _acc.push_back(frame);

    // If size does not match rather repeat frames or discard them.
    } else {
      if (_lastPatchMode == "repeat") {
        if (frame.size() == 0) {
          EXEC_DEBUG("VectorRealToTensor: 0 frames remaining.");

        } else {
          if (frame.size() < 10) {
            E_WARNING("VectorRealToTensor: Last patch produced by repeating the last " << frame.size() << " frames. May result in unreliable predictions.");
          }
          vector<vector<Real> > padded_frame = frame;

          for (int i = 0; i < _timeStamps; i++) {
            padded_frame.push_back(frame[i % frame.size()]);
          }

          EXEC_DEBUG("VectorRealToTensor: Repeating the remaining " << frame.size() << " frames to make one last patch.");
          _acc.push_back(padded_frame);
        }

      } else if (_lastPatchMode == "discard") {
        EXEC_DEBUG("VectorRealToTensor: Discarding last frames");

      } else {
        throw EssentiaException("VectorRealToTensor: Incomplete patch found "
                                "before reaching the end of the stream. This is not supposed to happen");
      }
    }
  }

  // We only push if when we have filled the whole batch
  // or if we have reached the end of the stream in
  // accumulate mode.
  if (_push) {
    vector<int> shape = _shape;
    int batchHopSize = _batchHopSize;

    // If we have been accumulating we have to get the
    // tensor's shape from the current status of the
    // accumulator.
    if (_accumulate) {
      shape[0] = _acc.size();
      batchHopSize = _acc.size();

      if (_acc.size() == 0) {
        throw EssentiaException("VectorRealToTensor: The stream has finished without enough frames to "
                                "produce a patch of the desired size. Consider setting the `lastPatchMode` "
                                "parameter to `repeat` in order to produce a batch.");
      }
    }

    Tensor<Real>& tensor = *(Tensor<Real> *)_tensor.getFirstToken();

    // Explicit convertion of std:vector to std::array<Eigen::Index> for Clang.
    std::array<Eigen::Index, TENSORRANK> shapeEigenIndex;
    std::copy_n(shape.begin(), TENSORRANK, shapeEigenIndex.begin());

    tensor.resize(shapeEigenIndex);

    for (int i = 0; i < shape[0]; i++) {      // Batch axis
      for (int j = 0; j < shape[2]; j++) {    // Time axis
        for (int k = 0; k < shape[3]; k++) {  // Freq axis
          tensor(i, 0, j, k) = _acc[i][j][k];
        }
      }
    }

    // Empty the accumulator.
    _acc.erase(_acc.begin(), _acc.begin() + batchHopSize);

    _push = false;
    outStatus = OK;
  }

  // Check if we should push in the next process().
  if (!_accumulate) {
    if ((int)_acc.size() >= _shape[0]) _push = true;
  }

  EXEC_DEBUG("releasing");
  releaseData();
  EXEC_DEBUG("released");
  return outStatus;
}

void VectorRealToTensor::reset() {
  _acc.assign(0, vector<vector<Real> >(_shape[1], vector<Real>(_shape[2], 0.0)));
  _push = false;
}

} // namespace streaming
} // namespace essentia
<|endoftext|>