<commit_before>/*
 * Copyright (C) 2008  Barracuda Networks, Inc.
 *
 * 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 WITHANY 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., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 *
 */

#include "gstthread.h"

#include <QStringList>
#include <QDir>
#include <QLibrary>
#include <QCoreApplication>
#include <QMutex>
#include <QWaitCondition>
#include <QCoreApplication>
#include <QQueue>
//#include <QStyle>
#include <QIcon>
#include <gst/gst.h>
#include "gstelements/static/gstelements.h"

namespace PsiMedia {

//----------------------------------------------------------------------------
// GstSession
//----------------------------------------------------------------------------
// converts Qt-ified commandline args back to C style
class CArgs
{
public:
	int argc;
	char **argv;

	CArgs()
	{
		argc = 0;
		argv = 0;
		count = 0;
		data = 0;
	}

	~CArgs()
	{
		if(count > 0)
		{
			for(int n = 0; n < count; ++n)
				delete [] data[n];
			free(argv);
			free(data);
		}
	}

	void set(const QStringList &args)
	{
		count = args.count();
		if(count == 0)
		{
			data = 0;
			argc = 0;
			argv = 0;
		}
		else
		{
			data = (char **)malloc(sizeof(char **) * count);
			argv = (char **)malloc(sizeof(char **) * count);
			for(int n = 0; n < count; ++n)
			{
				QByteArray cs = args[n].toLocal8Bit();
				data[n] = (char *)qstrdup(cs.data());
				argv[n] = data[n];
			}
			argc = count;
		}
	}

private:
	int count;
	char **data;
};

static void loadPlugins(const QString &pluginPath, bool print = false)
{
	if(print)
		qDebug("Loading plugins in [%s]\n", qPrintable(pluginPath));
	QDir dir(pluginPath);
	QStringList entryList = dir.entryList(QDir::Files);
	foreach(QString entry, entryList)
	{
		if(!QLibrary::isLibrary(entry))
			continue;
		QString filePath = dir.filePath(entry);
		GError *err = 0;
		GstPlugin *plugin = gst_plugin_load_file(
			filePath.toUtf8().data(), &err);
		if(!plugin)
		{
			if(print)
			{
				qDebug("**FAIL**: %s: %s\n", qPrintable(entry),
					err->message);
			}
			g_error_free(err);
			continue;
		}
		if(print)
		{
			qDebug("   OK   : %s name=[%s]\n", qPrintable(entry),
				gst_plugin_get_name(plugin));
		}
		gst_object_unref(plugin);
	}

	if(print)
		qDebug("\n");
}

static int compare_gst_version(int a1, int a2, int a3, int b1, int b2, int b3)
{
	if(a1 > b1)
		return 1;
	else if(a1 < b1)
		return -1;

	if(a2 > b2)
		return 1;
	else if(a2 < b2)
		return -1;

	if(a3 > b3)
		return 1;
	else if(a3 < b3)
		return -1;

	return 0;
}

class GstSession
{
public:
	CArgs args;
	QString version;
	bool success;

	GstSession(const QString &pluginPath = QString())
	{
		args.set(QCoreApplication::instance()->arguments());

		// ignore "system" plugins
		if(!pluginPath.isEmpty())
		{
			qputenv("GST_PLUGIN_SYSTEM_PATH", pluginPath.toLocal8Bit()); // not sure about windows
			//qputenv("GST_PLUGIN_PATH", "");
		}

		// you can also use NULLs here if you don't want to pass args
		GError *error;
		if(!gst_init_check(&args.argc, &args.argv, &error))
		{
			success = false;
			return;
		}

		guint major, minor, micro, nano;
		gst_version(&major, &minor, &micro, &nano);

		QString nano_str;
		if(nano == 1)
			nano_str = " (CVS)";
		else if(nano == 2)
			nano_str = " (Prerelease)";

		version.sprintf("%d.%d.%d%s", major, minor, micro,
			!nano_str.isEmpty() ? qPrintable(nano_str) : "");

		int need_maj = 1;
		int need_min = 4;
		int need_mic = 0;
		if(compare_gst_version(major, minor, micro, need_maj, need_min, need_mic) < 0)
		{
			qDebug("Need GStreamer version %d.%d.%d\n", need_maj, need_min, need_mic);
			success = false;
			return;
		}

		// manually load plugins?
		//if(!pluginPath.isEmpty())
		//	loadPlugins(pluginPath);

		//gstcustomelements_register();
		//gstelements_register();

		QStringList reqelem = QStringList()
			<< "opusenc" << "opusdec"
			<< "vorbisenc" << "vorbisdec"
			<< "theoraenc" << "theoradec"
			<< "rtpopuspay" << "rtpopusdepay"
			<< "rtpvorbispay" << "rtpvorbisdepay"
			<< "rtptheorapay" << "rtptheoradepay"
			<< "filesrc"
			<< "decodebin"
			<< "jpegdec"
			<< "oggmux" << "oggdemux"
			<< "audioconvert"
			<< "audioresample"
			<< "volume"
			<< "level"
			<< "videoconvert"
			<< "videorate"
			<< "videoscale"
			<< "rtpjitterbuffer"
			<< "liveadder"
		    << "appsink";

#if defined(Q_OS_MAC)
		reqelem
			<< "osxaudiosrc" << "osxaudiosink";
# ifdef HAVE_OSXVIDIO
		reqelem << "osxvideosrc";
# endif
#elif defined(Q_OS_LINUX)
			reqelem
			<< "v4l2src";
#elif defined(Q_OS_UNIX)
			reqelem
			<< "osssrc" << "osssink";
#elif defined(Q_OS_WIN)
			reqelem
			<< "directsoundsrc" << "directsoundsink"
			<< "ksvideosrc";
#endif

		foreach(const QString &name, reqelem)
		{
			GstElement *e = gst_element_factory_make(name.toLatin1().data(), NULL);
			if(!e)
			{
				qDebug("Unable to load element '%s'.\n", qPrintable(name));
				success = false;
				return;
			}

			g_object_unref(G_OBJECT(e));
		}

		success = true;
	}

	~GstSession()
	{
		// docs say to not bother with gst_deinit, but we'll do it
		//   anyway in case there's an issue with plugin unloading
		// update: there could be other gstreamer users, so we
		//   probably shouldn't call this.  also, it appears to crash
		//   on mac for at least one user..   maybe the function is
		//   not very well tested.
		//gst_deinit();
	}
};

//----------------------------------------------------------------------------
// GstMainLoop
//----------------------------------------------------------------------------

class GstMainLoop::Private
{
public:
    typedef struct {
      GSource         parent;
      GstMainLoop::Private *d;
    } BridgeQueueSource;

    GstMainLoop *q;
	QString pluginPath;
	GstSession *gstSession;
	bool success;
	GMainContext *mainContext;
	GMainLoop *mainLoop;
	QMutex m;
	QWaitCondition w;
    BridgeQueueSource *bridgeSource;
    int bridgeId;
    QQueue<QPair<GstMainLoop::ContextCallback,void*>> bridgeQueue;

	Private(GstMainLoop *q) : q(q),
		gstSession(0),
		success(false),
		mainContext(0),
		mainLoop(0)
	{
	}

	static gboolean cb_loop_started(gpointer data)
	{
		return ((Private *)data)->loop_started();
	}

	gboolean loop_started()
	{
		w.wakeOne();
		m.unlock();
        emit q->started();
		return FALSE;
	}

    static gboolean bridge_callback(gpointer data)
    {
        auto d = (GstMainLoop::Private*)data;
        while (d->bridgeQueue.size()) {
            d->m.lock();
            QPair<GstMainLoop::ContextCallback,void*> p;
            bool exist = d->bridgeQueue.size() > 0;
            if (exist);
                p = d->bridgeQueue.dequeue();
            d->m.unlock();
            if (exist)
                p.first(p.second);
        }

        return d->mainLoop == nullptr? FALSE: TRUE;
    }

    static gboolean bridge_prepare(GSource *source,gint *timeout_)
    {
        *timeout_ = -1;
        auto d = ((Private::BridgeQueueSource*)source)->d;
        QMutexLocker locker(&d->m);
        return d->bridgeQueue.size() > 0? TRUE: FALSE;
    }

    static gboolean bridge_check(GSource *source)
    {
        auto d = ((Private::BridgeQueueSource*)source)->d;
        QMutexLocker locker(&d->m);
        return d->bridgeQueue.size() > 0? TRUE: FALSE;
    }

    static gboolean bridge_dispatch(GSource *source,GSourceFunc callback,gpointer user_data)
    {
        if (callback(user_data))
            return TRUE;
        else
            return FALSE;
    }

};

GstMainLoop::GstMainLoop(const QString &resPath) :
	QObject()
{
	d = new Private(this);
    d->pluginPath = resPath;

    //create a variable of type GSourceFuncs
    static GSourceFuncs bridgeFuncs =
    {
        Private::bridge_prepare,
        Private::bridge_check,
        Private::bridge_dispatch,
        NULL,
        NULL,
        NULL
    };

    //create a new source
    d->bridgeSource = reinterpret_cast<Private::BridgeQueueSource*>(g_source_new (&bridgeFuncs, sizeof(Private::BridgeQueueSource)));
    d->bridgeSource->d = d;

	// HACK: if gstreamer initializes before certain Qt internal
	//   initialization occurs, then the app becomes unstable.
	//   I don't know what exactly needs to happen, or where the
	//   bug is, but if I fiddle with the default QStyle before
	//   initializing gstreamer, then this seems to solve it.
	//   it could be a bug in QCleanlooksStyle or QGtkStyle, which
	//   may conflict with separate Gtk initialization that may
	//   occur through gstreamer plugin loading.
	//{
	//	QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical, 0, 0);
	//}
}

GstMainLoop::~GstMainLoop()
{
	stop();
	delete d;
}

void GstMainLoop::stop()
{
    bool stopped = execInContext([this](void *data){
        g_main_loop_quit(d->mainLoop);
    }, this);

	if(stopped) {
		d->w.wait(&d->m);
	}
}

QString GstMainLoop::gstVersion() const
{
	QMutexLocker locker(&d->m);
	return d->gstSession->version;
}

GMainContext *GstMainLoop::mainContext()
{
	QMutexLocker locker(&d->m);
    return d->mainContext;
}

bool GstMainLoop::isInitialized() const
{
    QMutexLocker locker(&d->m);
    return d->success;
}

bool GstMainLoop::execInContext(ContextCallback cb, void *userData)
{
    QMutexLocker locker(&d->m);
    if (d->mainLoop) {
        d->bridgeQueue.enqueue({cb, userData});
        g_main_context_wakeup(d->mainContext);
        return true;
    }
    return false;
}

void GstMainLoop::init()
{
	//qDebug("GStreamer thread started\n");

	// this will be unlocked as soon as the mainloop runs
	d->m.lock();

	d->gstSession = new GstSession(d->pluginPath);

	// report error
	if(!d->gstSession->success)
	{
		d->success = false;
		delete d->gstSession;
		d->gstSession = 0;
		d->w.wakeOne();
		d->m.unlock();
		//qDebug("GStreamer thread completed (error)\n");
		emit finished();
	}

	d->success = true;

	//qDebug("Using GStreamer version %s\n", qPrintable(d->gstSession->version));

	d->mainContext = g_main_context_new();
    d->mainLoop = g_main_loop_new(d->mainContext, FALSE);

    //attach bridge source to context
    d->bridgeId = g_source_attach((GSource*)d->bridgeSource,d->mainContext);
    g_source_set_callback ((GSource*)d->bridgeSource, GstMainLoop::Private::bridge_callback, d, NULL);

	// deferred call to loop_started()
	GSource *timer = g_timeout_source_new(0);
	g_source_attach(timer, d->mainContext);
	g_source_set_callback(timer, GstMainLoop::Private::cb_loop_started, d, NULL);
    d->m.unlock();
    emit initialized();
}

void GstMainLoop::start()
{
    // kick off the event loop
	g_main_loop_run(d->mainLoop);

	QMutexLocker locker(&d->m);
	g_main_loop_unref(d->mainLoop);
	d->mainLoop = 0;
	g_main_context_unref(d->mainContext);
	d->mainContext = 0;
	delete d->gstSession;
	d->gstSession = 0;

	d->w.wakeOne();
    emit finished();
    //qDebug("GStreamer thread completed\n");
}

}
<commit_msg>Fixed invalid null condition<commit_after>/*
 * Copyright (C) 2008  Barracuda Networks, Inc.
 *
 * 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 WITHANY 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., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 *
 */

#include "gstthread.h"

#include <QStringList>
#include <QDir>
#include <QLibrary>
#include <QCoreApplication>
#include <QMutex>
#include <QWaitCondition>
#include <QCoreApplication>
#include <QQueue>
//#include <QStyle>
#include <QIcon>
#include <gst/gst.h>
#include "gstelements/static/gstelements.h"

namespace PsiMedia {

//----------------------------------------------------------------------------
// GstSession
//----------------------------------------------------------------------------
// converts Qt-ified commandline args back to C style
class CArgs
{
public:
	int argc;
	char **argv;

	CArgs()
	{
		argc = 0;
		argv = 0;
		count = 0;
		data = 0;
	}

	~CArgs()
	{
		if(count > 0)
		{
			for(int n = 0; n < count; ++n)
				delete [] data[n];
			free(argv);
			free(data);
		}
	}

	void set(const QStringList &args)
	{
		count = args.count();
		if(count == 0)
		{
			data = 0;
			argc = 0;
			argv = 0;
		}
		else
		{
			data = (char **)malloc(sizeof(char **) * count);
			argv = (char **)malloc(sizeof(char **) * count);
			for(int n = 0; n < count; ++n)
			{
				QByteArray cs = args[n].toLocal8Bit();
				data[n] = (char *)qstrdup(cs.data());
				argv[n] = data[n];
			}
			argc = count;
		}
	}

private:
	int count;
	char **data;
};

static void loadPlugins(const QString &pluginPath, bool print = false)
{
	if(print)
		qDebug("Loading plugins in [%s]\n", qPrintable(pluginPath));
	QDir dir(pluginPath);
	QStringList entryList = dir.entryList(QDir::Files);
	foreach(QString entry, entryList)
	{
		if(!QLibrary::isLibrary(entry))
			continue;
		QString filePath = dir.filePath(entry);
		GError *err = 0;
		GstPlugin *plugin = gst_plugin_load_file(
			filePath.toUtf8().data(), &err);
		if(!plugin)
		{
			if(print)
			{
				qDebug("**FAIL**: %s: %s\n", qPrintable(entry),
					err->message);
			}
			g_error_free(err);
			continue;
		}
		if(print)
		{
			qDebug("   OK   : %s name=[%s]\n", qPrintable(entry),
				gst_plugin_get_name(plugin));
		}
		gst_object_unref(plugin);
	}

	if(print)
		qDebug("\n");
}

static int compare_gst_version(int a1, int a2, int a3, int b1, int b2, int b3)
{
	if(a1 > b1)
		return 1;
	else if(a1 < b1)
		return -1;

	if(a2 > b2)
		return 1;
	else if(a2 < b2)
		return -1;

	if(a3 > b3)
		return 1;
	else if(a3 < b3)
		return -1;

	return 0;
}

class GstSession
{
public:
	CArgs args;
	QString version;
	bool success;

	GstSession(const QString &pluginPath = QString())
	{
		args.set(QCoreApplication::instance()->arguments());

		// ignore "system" plugins
		if(!pluginPath.isEmpty())
		{
			qputenv("GST_PLUGIN_SYSTEM_PATH", pluginPath.toLocal8Bit()); // not sure about windows
			//qputenv("GST_PLUGIN_PATH", "");
		}

		// you can also use NULLs here if you don't want to pass args
		GError *error;
		if(!gst_init_check(&args.argc, &args.argv, &error))
		{
			success = false;
			return;
		}

		guint major, minor, micro, nano;
		gst_version(&major, &minor, &micro, &nano);

		QString nano_str;
		if(nano == 1)
			nano_str = " (CVS)";
		else if(nano == 2)
			nano_str = " (Prerelease)";

		version.sprintf("%d.%d.%d%s", major, minor, micro,
			!nano_str.isEmpty() ? qPrintable(nano_str) : "");

		int need_maj = 1;
		int need_min = 4;
		int need_mic = 0;
		if(compare_gst_version(major, minor, micro, need_maj, need_min, need_mic) < 0)
		{
			qDebug("Need GStreamer version %d.%d.%d\n", need_maj, need_min, need_mic);
			success = false;
			return;
		}

		// manually load plugins?
		//if(!pluginPath.isEmpty())
		//	loadPlugins(pluginPath);

		//gstcustomelements_register();
		//gstelements_register();

		QStringList reqelem = QStringList()
			<< "opusenc" << "opusdec"
			<< "vorbisenc" << "vorbisdec"
			<< "theoraenc" << "theoradec"
			<< "rtpopuspay" << "rtpopusdepay"
			<< "rtpvorbispay" << "rtpvorbisdepay"
			<< "rtptheorapay" << "rtptheoradepay"
			<< "filesrc"
			<< "decodebin"
			<< "jpegdec"
			<< "oggmux" << "oggdemux"
			<< "audioconvert"
			<< "audioresample"
			<< "volume"
			<< "level"
			<< "videoconvert"
			<< "videorate"
			<< "videoscale"
			<< "rtpjitterbuffer"
			<< "liveadder"
		    << "appsink";

#if defined(Q_OS_MAC)
		reqelem
			<< "osxaudiosrc" << "osxaudiosink";
# ifdef HAVE_OSXVIDIO
		reqelem << "osxvideosrc";
# endif
#elif defined(Q_OS_LINUX)
			reqelem
			<< "v4l2src";
#elif defined(Q_OS_UNIX)
			reqelem
			<< "osssrc" << "osssink";
#elif defined(Q_OS_WIN)
			reqelem
			<< "directsoundsrc" << "directsoundsink"
			<< "ksvideosrc";
#endif

		foreach(const QString &name, reqelem)
		{
			GstElement *e = gst_element_factory_make(name.toLatin1().data(), NULL);
			if(!e)
			{
				qDebug("Unable to load element '%s'.\n", qPrintable(name));
				success = false;
				return;
			}

			g_object_unref(G_OBJECT(e));
		}

		success = true;
	}

	~GstSession()
	{
		// docs say to not bother with gst_deinit, but we'll do it
		//   anyway in case there's an issue with plugin unloading
		// update: there could be other gstreamer users, so we
		//   probably shouldn't call this.  also, it appears to crash
		//   on mac for at least one user..   maybe the function is
		//   not very well tested.
		//gst_deinit();
	}
};

//----------------------------------------------------------------------------
// GstMainLoop
//----------------------------------------------------------------------------

class GstMainLoop::Private
{
public:
    typedef struct {
      GSource         parent;
      GstMainLoop::Private *d;
    } BridgeQueueSource;

    GstMainLoop *q;
	QString pluginPath;
	GstSession *gstSession;
	bool success;
	GMainContext *mainContext;
	GMainLoop *mainLoop;
	QMutex m;
	QWaitCondition w;
    BridgeQueueSource *bridgeSource;
    int bridgeId;
    QQueue<QPair<GstMainLoop::ContextCallback,void*>> bridgeQueue;

	Private(GstMainLoop *q) : q(q),
		gstSession(0),
		success(false),
		mainContext(0),
		mainLoop(0)
	{
	}

	static gboolean cb_loop_started(gpointer data)
	{
		return ((Private *)data)->loop_started();
	}

	gboolean loop_started()
	{
		w.wakeOne();
		m.unlock();
        emit q->started();
		return FALSE;
	}

    static gboolean bridge_callback(gpointer data)
    {
        auto d = (GstMainLoop::Private*)data;
        while (d->bridgeQueue.size()) {
            d->m.lock();
            QPair<GstMainLoop::ContextCallback,void*> p;
            bool exist = d->bridgeQueue.size() > 0;
            if (exist)
                p = d->bridgeQueue.dequeue();
            d->m.unlock();
            if (exist)
                p.first(p.second);
        }

        return d->mainLoop == nullptr? FALSE: TRUE;
    }

    static gboolean bridge_prepare(GSource *source,gint *timeout_)
    {
        *timeout_ = -1;
        auto d = ((Private::BridgeQueueSource*)source)->d;
        QMutexLocker locker(&d->m);
        return d->bridgeQueue.size() > 0? TRUE: FALSE;
    }

    static gboolean bridge_check(GSource *source)
    {
        auto d = ((Private::BridgeQueueSource*)source)->d;
        QMutexLocker locker(&d->m);
        return d->bridgeQueue.size() > 0? TRUE: FALSE;
    }

    static gboolean bridge_dispatch(GSource *source,GSourceFunc callback,gpointer user_data)
    {
        if (callback(user_data))
            return TRUE;
        else
            return FALSE;
    }

};

GstMainLoop::GstMainLoop(const QString &resPath) :
	QObject()
{
	d = new Private(this);
    d->pluginPath = resPath;

    //create a variable of type GSourceFuncs
    static GSourceFuncs bridgeFuncs =
    {
        Private::bridge_prepare,
        Private::bridge_check,
        Private::bridge_dispatch,
        NULL,
        NULL,
        NULL
    };

    //create a new source
    d->bridgeSource = reinterpret_cast<Private::BridgeQueueSource*>(g_source_new (&bridgeFuncs, sizeof(Private::BridgeQueueSource)));
    d->bridgeSource->d = d;

	// HACK: if gstreamer initializes before certain Qt internal
	//   initialization occurs, then the app becomes unstable.
	//   I don't know what exactly needs to happen, or where the
	//   bug is, but if I fiddle with the default QStyle before
	//   initializing gstreamer, then this seems to solve it.
	//   it could be a bug in QCleanlooksStyle or QGtkStyle, which
	//   may conflict with separate Gtk initialization that may
	//   occur through gstreamer plugin loading.
	//{
	//	QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical, 0, 0);
	//}
}

GstMainLoop::~GstMainLoop()
{
	stop();
	delete d;
}

void GstMainLoop::stop()
{
    bool stopped = execInContext([this](void *data){
        g_main_loop_quit(d->mainLoop);
    }, this);

	if(stopped) {
		d->w.wait(&d->m);
	}
}

QString GstMainLoop::gstVersion() const
{
	QMutexLocker locker(&d->m);
	return d->gstSession->version;
}

GMainContext *GstMainLoop::mainContext()
{
	QMutexLocker locker(&d->m);
    return d->mainContext;
}

bool GstMainLoop::isInitialized() const
{
    QMutexLocker locker(&d->m);
    return d->success;
}

bool GstMainLoop::execInContext(ContextCallback cb, void *userData)
{
    QMutexLocker locker(&d->m);
    if (d->mainLoop) {
        d->bridgeQueue.enqueue({cb, userData});
        g_main_context_wakeup(d->mainContext);
        return true;
    }
    return false;
}

void GstMainLoop::init()
{
	//qDebug("GStreamer thread started\n");

	// this will be unlocked as soon as the mainloop runs
	d->m.lock();

	d->gstSession = new GstSession(d->pluginPath);

	// report error
	if(!d->gstSession->success)
	{
		d->success = false;
		delete d->gstSession;
		d->gstSession = 0;
		d->w.wakeOne();
		d->m.unlock();
		//qDebug("GStreamer thread completed (error)\n");
		emit finished();
	}

	d->success = true;

	//qDebug("Using GStreamer version %s\n", qPrintable(d->gstSession->version));

	d->mainContext = g_main_context_new();
    d->mainLoop = g_main_loop_new(d->mainContext, FALSE);

    //attach bridge source to context
    d->bridgeId = g_source_attach((GSource*)d->bridgeSource,d->mainContext);
    g_source_set_callback ((GSource*)d->bridgeSource, GstMainLoop::Private::bridge_callback, d, NULL);

	// deferred call to loop_started()
	GSource *timer = g_timeout_source_new(0);
	g_source_attach(timer, d->mainContext);
	g_source_set_callback(timer, GstMainLoop::Private::cb_loop_started, d, NULL);
    d->m.unlock();
    emit initialized();
}

void GstMainLoop::start()
{
    // kick off the event loop
	g_main_loop_run(d->mainLoop);

	QMutexLocker locker(&d->m);
	g_main_loop_unref(d->mainLoop);
	d->mainLoop = 0;
	g_main_context_unref(d->mainContext);
	d->mainContext = 0;
	delete d->gstSession;
	d->gstSession = 0;

	d->w.wakeOne();
    emit finished();
    //qDebug("GStreamer thread completed\n");
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <windows.h>
#include <fstream>
#include <winsock.h>
#include <ws2tcpip.h>

#define CONNECTION_PTR_OFFSET      0x012705C4
#define SESSIONKEY_OFFSET          0x508
#define VERSION                    "3.2.2"
#define CONFIG_NAME                "tiawps_reader_config.txt"
#define SESSIONKEY_LENGTH          40
struct Config
{
    std::string tiawpsHost;
    std::string tiawpsPort;

    bool readConfig(char* fileName)
    {
        std::ifstream inFile;
        inFile.open(CONFIG_NAME);
        if(!inFile)
        {
            printf("Couldn't open config file %s\n", fileName);
            return false;
        }
        if (inFile >> tiawpsHost &&
            inFile >> tiawpsPort)
        {
            printf("loaded config: host = %s, port = %s\n",
                tiawpsHost.c_str(), tiawpsPort.c_str());
            int tiawpsPort = atoi(this->tiawpsPort.c_str());
            if(tiawpsPort < 0 || tiawpsPort > 0xFFFF)
            {
                printf("invalid port %u!\n", tiawpsPort);
                return false;
            }
            return true;
        }
        return false;
    }
};

void dumpByteArray(char* array, int size)
{
     for(int i=0; i<size;i++)
         printf("%02X ", (unsigned char)array[i]);
}

void sendToTiawps(Config const& config, char* sessionKey)
{
     WSADATA wsaData;
     SOCKET ConnectSocket = INVALID_SOCKET;
     struct addrinfo *result = NULL, *ptr = NULL, hints;

     int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
     if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return;
    }
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    iResult = getaddrinfo(config.tiawpsHost.c_str(), config.tiawpsPort.c_str(), &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return;
    }

    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next)
    {
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Error at socket(): %ld\n", WSAGetLastError());
            freeaddrinfo(result);
            WSACleanup();
            return;
        }
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }
    freeaddrinfo(result);
    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to tiawps!\n");
        WSACleanup();
        return;
    }
    int sendBufSize = SESSIONKEY_LENGTH;
    char* sendbuf = new char[sendBufSize];
    memset(sendbuf, 0, sendBufSize);
    memcpy(sendbuf, sessionKey, SESSIONKEY_LENGTH);
    iResult = send( ConnectSocket, sendbuf, sendBufSize, 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return;
    }
    printf("Bytes Sent: %ld\n", iResult);
    closesocket(ConnectSocket);
    WSACleanup();
}

bool readSessionKey(char* sessionKey)
{
    HANDLE hToken;
    OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );

    TOKEN_PRIVILEGES tp = { 0 };
    LUID luid;
    DWORD cb = sizeof(TOKEN_PRIVILEGES);
    if( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid ) )
        return false;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL );
    CloseHandle(hToken);

    unsigned long WindowsPID;

    char applicationName[] = "World of Warcraft";

    HWND WindowsHandle = FindWindow(0, applicationName);
    if (!WindowsHandle)
    {
        printf("Window %s not found!\n", applicationName);
        return false;
    }

    GetWindowThreadProcessId(WindowsHandle, &WindowsPID);
    HANDLE wow_process_handle = OpenProcess(PROCESS_ALL_ACCESS, false, WindowsPID);

    DWORD number_of_read_bytes=0;

    char pointer[4] = {'\0'};
    ReadProcessMemory(wow_process_handle, (LPCVOID)CONNECTION_PTR_OFFSET, pointer, 4, &number_of_read_bytes);

    if(number_of_read_bytes != 4)
    {
        printf("couldn't read pointer, just read %u bytes instead of 4\n", number_of_read_bytes);
        CloseHandle(wow_process_handle);
        return false;
    }
    // convert bytes to pointer
    unsigned int sessionKeyPosition = 0;
    memcpy(&sessionKeyPosition, pointer, 4);
    printf("Got pointer: %#X\n", sessionKeyPosition);

    number_of_read_bytes = 0;
    ReadProcessMemory(wow_process_handle, (LPCVOID)(SESSIONKEY_OFFSET+sessionKeyPosition), sessionKey, SESSIONKEY_LENGTH, &number_of_read_bytes);
    CloseHandle(wow_process_handle);
    if(number_of_read_bytes != SESSIONKEY_LENGTH)
    {
        printf("couldn't read sessionkey, read %u bytes instaed of %u\n", number_of_read_bytes, SESSIONKEY_LENGTH);
        return false;
    }
    printf("Got sessionkey: ");
    dumpByteArray(sessionKey, SESSIONKEY_LENGTH);
    printf("\n");

    printf("checking plausibility\n");
    bool foundNonZero = false;
    for(int i=0; i< SESSIONKEY_LENGTH; i++)
        if(sessionKey[i]!=0)
            foundNonZero=true;

    if(!foundNonZero)
    {
        printf("sessionKey contains only of zeros - unlikely..\n");
        return false;
    }

    return true;
}
int main()
{
    printf("Tiawps sessionkey reader for version %s started\n", VERSION);
    printf("loading config\n");
    Config cfg;
    if(!cfg.readConfig(CONFIG_NAME))
        return 1;

    char sessionKey[SESSIONKEY_LENGTH] = {'\0'};

   while(!readSessionKey(sessionKey))
   {
       printf("reading sessionkey failed - will try again in 1 second\n");
       Sleep(1000);
   }

    printf("trying to send it to tiawps dumper\n");
    sendToTiawps(cfg, sessionKey);

    return 0;
}

<commit_msg>update sessionkey offset<commit_after>#include <iostream>
#include <windows.h>
#include <fstream>
#include <winsock.h>
#include <ws2tcpip.h>

#define CONNECTION_PTR_OFFSET      0x00C923C0
#define SESSIONKEY_OFFSET          0x508
#define VERSION                    "3.2.2"
#define CONFIG_NAME                "tiawps_reader_config.txt"
#define SESSIONKEY_LENGTH          40
struct Config
{
    std::string tiawpsHost;
    std::string tiawpsPort;

    bool readConfig(char* fileName)
    {
        std::ifstream inFile;
        inFile.open(CONFIG_NAME);
        if(!inFile)
        {
            printf("Couldn't open config file %s\n", fileName);
            return false;
        }
        if (inFile >> tiawpsHost &&
            inFile >> tiawpsPort)
        {
            printf("loaded config: host = %s, port = %s\n",
                tiawpsHost.c_str(), tiawpsPort.c_str());
            int tiawpsPort = atoi(this->tiawpsPort.c_str());
            if(tiawpsPort < 0 || tiawpsPort > 0xFFFF)
            {
                printf("invalid port %u!\n", tiawpsPort);
                return false;
            }
            return true;
        }
        return false;
    }
};

void dumpByteArray(char* array, int size)
{
     for(int i=0; i<size;i++)
         printf("%02X ", (unsigned char)array[i]);
}

void sendToTiawps(Config const& config, char* sessionKey)
{
     WSADATA wsaData;
     SOCKET ConnectSocket = INVALID_SOCKET;
     struct addrinfo *result = NULL, *ptr = NULL, hints;

     int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
     if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return;
    }
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    iResult = getaddrinfo(config.tiawpsHost.c_str(), config.tiawpsPort.c_str(), &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return;
    }

    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next)
    {
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Error at socket(): %ld\n", WSAGetLastError());
            freeaddrinfo(result);
            WSACleanup();
            return;
        }
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }
    freeaddrinfo(result);
    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to tiawps!\n");
        WSACleanup();
        return;
    }
    int sendBufSize = SESSIONKEY_LENGTH;
    char* sendbuf = new char[sendBufSize];
    memset(sendbuf, 0, sendBufSize);
    memcpy(sendbuf, sessionKey, SESSIONKEY_LENGTH);
    iResult = send( ConnectSocket, sendbuf, sendBufSize, 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return;
    }
    printf("Bytes Sent: %ld\n", iResult);
    closesocket(ConnectSocket);
    WSACleanup();
}

bool readSessionKey(char* sessionKey)
{
    HANDLE hToken;
    OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );

    TOKEN_PRIVILEGES tp = { 0 };
    LUID luid;
    DWORD cb = sizeof(TOKEN_PRIVILEGES);
    if( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid ) )
        return false;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL );
    CloseHandle(hToken);

    unsigned long WindowsPID;

    char applicationName[] = "World of Warcraft";

    HWND WindowsHandle = FindWindow(0, applicationName);
    if (!WindowsHandle)
    {
        printf("Window %s not found!\n", applicationName);
        return false;
    }

    GetWindowThreadProcessId(WindowsHandle, &WindowsPID);
    HANDLE wow_process_handle = OpenProcess(PROCESS_ALL_ACCESS, false, WindowsPID);

    DWORD number_of_read_bytes=0;

    char pointer[4] = {'\0'};
    ReadProcessMemory(wow_process_handle, (LPCVOID)CONNECTION_PTR_OFFSET, pointer, 4, &number_of_read_bytes);

    if(number_of_read_bytes != 4)
    {
        printf("couldn't read pointer, just read %u bytes instead of 4\n", number_of_read_bytes);
        CloseHandle(wow_process_handle);
        return false;
    }
    // convert bytes to pointer
    unsigned int sessionKeyPosition = 0;
    memcpy(&sessionKeyPosition, pointer, 4);
    printf("Got pointer: %#X\n", sessionKeyPosition);

    number_of_read_bytes = 0;
    ReadProcessMemory(wow_process_handle, (LPCVOID)(SESSIONKEY_OFFSET+sessionKeyPosition), sessionKey, SESSIONKEY_LENGTH, &number_of_read_bytes);
    CloseHandle(wow_process_handle);
    if(number_of_read_bytes != SESSIONKEY_LENGTH)
    {
        printf("couldn't read sessionkey, read %u bytes instaed of %u\n", number_of_read_bytes, SESSIONKEY_LENGTH);
        return false;
    }
    printf("Got sessionkey: ");
    dumpByteArray(sessionKey, SESSIONKEY_LENGTH);
    printf("\n");

    printf("checking plausibility\n");
    bool foundNonZero = false;
    for(int i=0; i< SESSIONKEY_LENGTH; i++)
        if(sessionKey[i]!=0)
            foundNonZero=true;

    if(!foundNonZero)
    {
        printf("sessionKey contains only of zeros - unlikely..\n");
        return false;
    }

    return true;
}
int main()
{
    printf("Tiawps sessionkey reader for version %s started\n", VERSION);
    printf("loading config\n");
    Config cfg;
    if(!cfg.readConfig(CONFIG_NAME))
        return 1;

    char sessionKey[SESSIONKEY_LENGTH] = {'\0'};

   while(!readSessionKey(sessionKey))
   {
       printf("reading sessionkey failed - will try again in 1 second\n");
       Sleep(1000);
   }

    printf("trying to send it to tiawps dumper\n");
    sendToTiawps(cfg, sessionKey);

    return 0;
}

<|endoftext|>


<commit_before>//
// InvalidCharacter.cpp
// json
//
// Created by Mathieu Garaud on 24/07/16.
//
// MIT License
//
// Copyright © 2016 Pretty Simple
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#include "InvalidCharacter.hpp"

#include "../context/ParseErrorContext.hpp"
#include "../Document.hpp"
#include "../std/OStringStream.hpp"
#include <ios>
#include <iostream>

using namespace json;

InvalidCharacter::InvalidCharacter(const std::string& message, const ParseErrorContext* errorCtx) : std::exception()
, _what(":0:0: error: ???\r\n")
{
    OStringStream whatBuf("", std::ios::ate);
    OStringStream extractBuf("", std::ios::ate);

    if (errorCtx != nullptr)
    {
        std::istream* stream = errorCtx->stream;
        if (stream->good())
        {
            const std::istream::pos_type maxCharLog(40);
            const auto current = stream->tellg();
            std::istream::pos_type firstBye(0);
            if (current > (maxCharLog+std::istream::pos_type(2)))
                firstBye = current-maxCharLog-std::istream::pos_type(1);
            stream->seekg(firstBye);

            std::uint32_t c = 0;

            OStringStream cursorErrorBuf("", std::ios::ate);
            bool isCursorWritten = false;

            for (c = nextChar(stream, errorCtx->enc);!stream->eof() && !stream->bad();c = nextChar(stream, errorCtx->enc))
            {
                const auto now = stream->tellg();
                if (c == '\r' || c == '\n')
                {
                    if (now <= current)
                    {
                        extractBuf.clear();
                        extractBuf.seekp(std::ios::beg);
                        cursorErrorBuf.clear();
                        cursorErrorBuf.seekp(std::ios::beg);
                    }
                    else
                        break;
                }
                else
                {
                    writeChar(extractBuf, c);
                    if (now < current)
                        cursorErrorBuf << (c == '\t'?'\t':' ');
                    else if (!isCursorWritten)
                    {
                        //cursorErrorBuf << "\033[32m";
                        cursorErrorBuf << '^';
                        isCursorWritten = true;
                    }
                }
                if (now >= (current + maxCharLog))
                    break;
            }

            extractBuf << '\r' << '\n' << cursorErrorBuf.str();
        }
    }
    whatBuf << errorCtx->filename << ':' << (errorCtx == nullptr?0:errorCtx->line) << ':' << (errorCtx == nullptr?0:errorCtx->column) << ": error: "<< message << '\r' << '\n' << extractBuf.str() << '\r' << '\n';
    _what = whatBuf.str();
}
InvalidCharacter::InvalidCharacter(InvalidCharacter&& other) noexcept : std::exception(std::move(other))
, _what(std::move(other._what))
{
}
InvalidCharacter& InvalidCharacter::operator =(InvalidCharacter&& other) noexcept
{
    _what = std::move(other._what);
    std::exception::operator=(std::move(other));
    return *this;
}

void InvalidCharacter::writeChar(OStringStream& buffer, const std::uint32_t c) const noexcept
{
    if (c <= 0x7F)
        buffer << static_cast<char>(c);
    else if (c <= 0x7FF)
        buffer << static_cast<char>((0x1F & (c >> 6)) | 0xC0) << static_cast<char>((0x3F & c) | 0x80);
    else if (c <= 0xFFFF)
        buffer << static_cast<char>((0x0F & (c >> 12)) | 0xE0) << static_cast<char>((0x3F & (c >> 6)) | 0x80) << static_cast<char>((0x3F & c) | 0x80);
    else if (c <= 0x10FFFF)
        buffer << static_cast<char>((0x07 & (c >> 18)) | 0xF0) << static_cast<char>((0x3F & (c >> 12)) | 0x80) << static_cast<char>((0x3F & (c >> 6)) | 0x80) <<static_cast<char>((0x3F & c) | 0x80);
}

std::uint32_t InvalidCharacter::nextChar(std::istream* stream, Encoding enc) const noexcept
{
    std::uint8_t unicodeCount = 0;
    std::istream::char_type ch = 0;
    std::uint8_t uCh = 0;
    std::uint32_t c = 0;

    for (stream->get(ch); !stream->eof() && !stream->bad(); stream->get(ch))
    {
        if (enc == Encoding::UTF8)
        {
            uCh = static_cast<std::uint8_t>(ch);
            if (unicodeCount == 0)
            {
                c = 0;
                if (uCh <= 0x7F)
                {
                    c = uCh;
                    unicodeCount = 0;
                }
                else if (uCh <= 0xDF)
                {
                    c = uCh & 0x1F;
                    c <<= 6;
                    unicodeCount = 1;
                }
                else if (uCh <= 0xEF)
                {
                    c = uCh & 0x0F;
                    c <<= 12;
                    unicodeCount = 2;
                }
                else if (uCh <= 0xFF)
                {
                    c = uCh & 0x07;
                    c <<= 18;
                    unicodeCount = 3;
                }
            }
            else if (uCh >= 0x80 && uCh <= 0xBF)
            {
                --unicodeCount;
                c |= static_cast<std::uint32_t>(0x003F & uCh) << (6*unicodeCount);
            }
            else // Just in case you start reading a character in a middle of UTF-8 sequence or it's invalid.
            {
                c = 0xFFFD;
                unicodeCount = 0;
            }
            if (unicodeCount == 0)
                break;
        }
        else if (enc == Encoding::UTF16)
        {
            if (unicodeCount == 0)
            {
                c = 0;
                c |= uCh;
                c <<= 8;
                unicodeCount=1;
            }
            else if (--unicodeCount == 0)
            {
                c |= uCh;
                if (c >= 0xD800 && c <= 0xDFFF)
                {
                    c &= 0x3FF;
                    c <<=10;
                    unicodeCount=3; // It's a nasty trick to avoid an extra variable for surrogate characters.
                }
            }
            else if (unicodeCount == 2)
            {
                std::uint16_t tmp = uCh;
                tmp &= 0x03;
                tmp <<= 8;
                c |= tmp;
            }
            else if (unicodeCount == 1)
            {
                c |= uCh;
                c |= 0x10000;
                unicodeCount=0;
            }
            if (unicodeCount == 0)
                break;
        }
        else if (enc == Encoding::UTF32)
        {
            if (unicodeCount == 0)
            {
                c = 0;
                c |= uCh;
                c <<= 24;
                unicodeCount=3;
            }
            else
            {
                unicodeCount--;
                std::uint32_t tmp = uCh;
                tmp <<= (unicodeCount*8);
                c |= tmp;
            }
            if (unicodeCount == 0)
                break;
        }
    }

    return c;
}

const char* InvalidCharacter::what() const noexcept
{
    return _what.c_str();
}
<commit_msg>Fix a potential bug thanks to the static analyzer<commit_after>//
// InvalidCharacter.cpp
// json
//
// Created by Mathieu Garaud on 24/07/16.
//
// MIT License
//
// Copyright © 2016 Pretty Simple
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#include "InvalidCharacter.hpp"

#include "../context/ParseErrorContext.hpp"
#include "../Document.hpp"
#include "../std/OStringStream.hpp"
#include <ios>
#include <iostream>

using namespace json;

InvalidCharacter::InvalidCharacter(const std::string& message, const ParseErrorContext* errorCtx) : std::exception()
, _what(":0:0: error: ???\r\n")
{
    OStringStream whatBuf("", std::ios::ate);
    OStringStream extractBuf("", std::ios::ate);

    if (errorCtx != nullptr)
    {
        std::istream* stream = errorCtx->stream;
        if (stream->good())
        {
            const std::istream::pos_type maxCharLog(40);
            const auto current = stream->tellg();
            std::istream::pos_type firstBye(0);
            if (current > (maxCharLog+std::istream::pos_type(2)))
                firstBye = current-maxCharLog-std::istream::pos_type(1);
            stream->seekg(firstBye);

            std::uint32_t c = 0;

            OStringStream cursorErrorBuf("", std::ios::ate);
            bool isCursorWritten = false;

            for (c = nextChar(stream, errorCtx->enc);!stream->eof() && !stream->bad();c = nextChar(stream, errorCtx->enc))
            {
                const auto now = stream->tellg();
                if (c == '\r' || c == '\n')
                {
                    if (now <= current)
                    {
                        extractBuf.clear();
                        extractBuf.seekp(std::ios::beg);
                        cursorErrorBuf.clear();
                        cursorErrorBuf.seekp(std::ios::beg);
                    }
                    else
                        break;
                }
                else
                {
                    writeChar(extractBuf, c);
                    if (now < current)
                        cursorErrorBuf << (c == '\t'?'\t':' ');
                    else if (!isCursorWritten)
                    {
                        //cursorErrorBuf << "\033[32m";
                        cursorErrorBuf << '^';
                        isCursorWritten = true;
                    }
                }
                if (now >= (current + maxCharLog))
                    break;
            }

            extractBuf << '\r' << '\n' << cursorErrorBuf.str();
        }
    }
    whatBuf << (errorCtx == nullptr?"":errorCtx->filename) << ':' << (errorCtx == nullptr?0:errorCtx->line) << ':' << (errorCtx == nullptr?0:errorCtx->column) << ": error: "<< message << '\r' << '\n' << extractBuf.str() << '\r' << '\n';
    _what = whatBuf.str();
}
InvalidCharacter::InvalidCharacter(InvalidCharacter&& other) noexcept : std::exception(std::move(other))
, _what(std::move(other._what))
{
}
InvalidCharacter& InvalidCharacter::operator =(InvalidCharacter&& other) noexcept
{
    _what = std::move(other._what);
    std::exception::operator=(std::move(other));
    return *this;
}

void InvalidCharacter::writeChar(OStringStream& buffer, const std::uint32_t c) const noexcept
{
    if (c <= 0x7F)
        buffer << static_cast<char>(c);
    else if (c <= 0x7FF)
        buffer << static_cast<char>((0x1F & (c >> 6)) | 0xC0) << static_cast<char>((0x3F & c) | 0x80);
    else if (c <= 0xFFFF)
        buffer << static_cast<char>((0x0F & (c >> 12)) | 0xE0) << static_cast<char>((0x3F & (c >> 6)) | 0x80) << static_cast<char>((0x3F & c) | 0x80);
    else if (c <= 0x10FFFF)
        buffer << static_cast<char>((0x07 & (c >> 18)) | 0xF0) << static_cast<char>((0x3F & (c >> 12)) | 0x80) << static_cast<char>((0x3F & (c >> 6)) | 0x80) <<static_cast<char>((0x3F & c) | 0x80);
}

std::uint32_t InvalidCharacter::nextChar(std::istream* stream, Encoding enc) const noexcept
{
    std::uint8_t unicodeCount = 0;
    std::istream::char_type ch = 0;
    std::uint8_t uCh = 0;
    std::uint32_t c = 0;

    for (stream->get(ch); !stream->eof() && !stream->bad(); stream->get(ch))
    {
        if (enc == Encoding::UTF8)
        {
            uCh = static_cast<std::uint8_t>(ch);
            if (unicodeCount == 0)
            {
                c = 0;
                if (uCh <= 0x7F)
                {
                    c = uCh;
                    unicodeCount = 0;
                }
                else if (uCh <= 0xDF)
                {
                    c = uCh & 0x1F;
                    c <<= 6;
                    unicodeCount = 1;
                }
                else if (uCh <= 0xEF)
                {
                    c = uCh & 0x0F;
                    c <<= 12;
                    unicodeCount = 2;
                }
                else if (uCh <= 0xFF)
                {
                    c = uCh & 0x07;
                    c <<= 18;
                    unicodeCount = 3;
                }
            }
            else if (uCh >= 0x80 && uCh <= 0xBF)
            {
                --unicodeCount;
                c |= static_cast<std::uint32_t>(0x003F & uCh) << (6*unicodeCount);
            }
            else // Just in case you start reading a character in a middle of UTF-8 sequence or it's invalid.
            {
                c = 0xFFFD;
                unicodeCount = 0;
            }
            if (unicodeCount == 0)
                break;
        }
        else if (enc == Encoding::UTF16)
        {
            if (unicodeCount == 0)
            {
                c = 0;
                c |= uCh;
                c <<= 8;
                unicodeCount=1;
            }
            else if (--unicodeCount == 0)
            {
                c |= uCh;
                if (c >= 0xD800 && c <= 0xDFFF)
                {
                    c &= 0x3FF;
                    c <<=10;
                    unicodeCount=3; // It's a nasty trick to avoid an extra variable for surrogate characters.
                }
            }
            else if (unicodeCount == 2)
            {
                std::uint16_t tmp = uCh;
                tmp &= 0x03;
                tmp <<= 8;
                c |= tmp;
            }
            else if (unicodeCount == 1)
            {
                c |= uCh;
                c |= 0x10000;
                unicodeCount=0;
            }
            if (unicodeCount == 0)
                break;
        }
        else if (enc == Encoding::UTF32)
        {
            if (unicodeCount == 0)
            {
                c = 0;
                c |= uCh;
                c <<= 24;
                unicodeCount=3;
            }
            else
            {
                unicodeCount--;
                std::uint32_t tmp = uCh;
                tmp <<= (unicodeCount*8);
                c |= tmp;
            }
            if (unicodeCount == 0)
                break;
        }
    }

    return c;
}

const char* InvalidCharacter::what() const noexcept
{
    return _what.c_str();
}
<|endoftext|>


<commit_before>#include "AndroidServiceHandler.h"
#include "protocol/AmmmoMessages.pb.h"

#include <iostream>

#include "ace/OS_NS_errno.h"

extern std::string gatewayAddress;
extern int gatewayPort;

int AndroidServiceHandler::open(void *ptr) {
  if(super::open(ptr) == -1) {
    return -1;

  }
  state = READING_SIZE;
  dataSize = 0;
  checksum = 0;
  collectedData = NULL;
  position = 0;

  gatewayConnector = new GatewayConnector(this);
}

int AndroidServiceHandler::handle_input(ACE_HANDLE fd) {
  //std::cout << "In handle_input" << std::endl << std::flush;
  int count = 0;

  if(state == READING_SIZE) {
    count = this->peer().recv_n(&dataSize, sizeof(dataSize));
    //std::cout << "SIZE Read " << count << " bytes" << std::endl << std::flush;
  } else if(state == READING_CHECKSUM) {
    count = this->peer().recv_n(&checksum, sizeof(checksum));
    //std::cout << "SUM Read " << count << " bytes" << std::endl << std::flush;
  } else if(state == READING_DATA) {
    count = this->peer().recv(collectedData + position, dataSize - position);
    //std::cout << "DATA Read " << count << " bytes" << std::endl << std::flush;
  } else {
    std::cout << "Invalid state!" << std::endl << std::flush;
  }

  if(count > 0) {
    if(state == READING_SIZE) {
      collectedData = new char[dataSize];
      position = 0;
      //std::cout << "Got data size (" << dataSize << ")" << std::endl << std::flush;
      state = READING_CHECKSUM;
    } else if(state == READING_CHECKSUM) {
      //std::cout << "Got data checksum (" << checksum << ")" << std::endl << std::flush;
      state = READING_DATA;
    } else if(state == READING_DATA) {
      //std::cout << "Got some data..." << std::endl << std::flush;
      position += count;
      if(position == dataSize) {
        //std::cout << "Got all the data... processing" << std::endl << std::flush;
        processData(collectedData, dataSize, checksum);
        //std::cout << "Processsing complete.  Deleting buffer." << std::endl << std::flush;
        delete[] collectedData;
        collectedData = NULL;
        dataSize = 0;
        position = 0;
        state = READING_SIZE;
      }
    }
  } else if(count == 0) {
    std::cout << "Connection closed." << std::endl << std::flush;
    return -1;
  } else if(count == -1 && ACE_OS::last_error () != EWOULDBLOCK) {
    std::cout << "Socket error occurred. (" << ACE_OS::last_error() << ")" << std::endl << std::flush;
    return -1;
  }
  //std::cout << "Leaving handle_input()" << std::endl << std::flush;
  return 0;
}

void AndroidServiceHandler::sendData(ammmo::protocol::MessageWrapper &msg) {
  /*Fixme: potential deadlock here
  unsigned int messageSize = msg.ByteSize();
  char *messageToSend = new char[messageSize];
  msg.SerializeToArray(messageToSend, messageSize);
  unsigned int messageChecksum = ACE::crc32(messageToSend, messageSize);

  ACE_Message_Block *messageSizeBlock = new ACE_Message_Block(sizeof(messageSize));
  messageSizeBlock->copy((char *) &messageSize, sizeof(messageSize));
  this->putq(messageSizeBlock);

  ACE_Message_Block *messageChecksumBlock = new ACE_Message_Block(sizeof(messageChecksum));
  messageChecksumBlock->copy((char *) &messageChecksum, sizeof(messageChecksum));
  this->putq(messageChecksumBlock);

  ACE_Message_Block *messageToSendBlock = new ACE_Message_Block(messageSize);
  messageToSendBlock->copy(messageToSend, messageSize);
  this->putq(messageToSendBlock);

  this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);*/

  unsigned int messageSize = msg.ByteSize();
  char *messageToSend = new char[messageSize];
  msg.SerializeToArray(messageToSend, messageSize);
  unsigned int messageChecksum = ACE::crc32(messageToSend, messageSize);

  this->peer().send_n(&messageSize, sizeof(messageSize));
  this->peer().send_n(&messageChecksum, sizeof(messageChecksum));
  this->peer().send_n(messageToSend, messageSize);
}

int AndroidServiceHandler::processData(char *data, unsigned int messageSize, unsigned int messageChecksum) {
  //Validate checksum
  unsigned int calculatedChecksum = ACE::crc32(data, messageSize);
  if(calculatedChecksum != messageChecksum) {
    std::cout << "Invalid checksum--  we've been sent bad data (perhaps a message size mismatch?)" << std::endl << std::flush;
    return -1;
  }

  //checksum is valid; parse the data
  ammmo::protocol::MessageWrapper msg;
  bool result = msg.ParseFromArray(data, messageSize);
  if(result == false) {
    std::cout << "MessageWrapper could not be deserialized." << std::endl;
    std::cout << "Client must have sent something that isn't a protocol buffer (or the wrong type)." << std::endl << std::flush;
    return -1;
  }
  //std::cout << "Message Received: " << msg.DebugString() << std::endl << std::flush;

  if(msg.type() == ammmo::protocol::MessageWrapper_MessageType_AUTHENTICATION_MESSAGE) {
    std::cout << "Received Authentication Message..." << std::endl << std::flush;
    if(gatewayConnector != NULL) {
      ammmo::protocol::AuthenticationMessage authMessage = msg.authentication_message();
      gatewayConnector->associateDevice(authMessage.device_id(), authMessage.user_id(), authMessage.user_key());
    }
  } else if(msg.type() == ammmo::protocol::MessageWrapper_MessageType_DATA_MESSAGE) {
    std::cout << "Received Data Message..." << std::endl << std::flush;
    if(gatewayConnector != NULL) {
      ammmo::protocol::DataMessage dataMessage = msg.data_message();
      gatewayConnector->pushData(dataMessage.uri(), dataMessage.mime_type(), dataMessage.data());
    }
  } else if(msg.type() == ammmo::protocol::MessageWrapper_MessageType_SUBSCRIBE_MESSAGE) {
    std::cout << "Received Subscribe Message..." << std::endl << std::flush;
    if(gatewayConnector != NULL) {
      ammmo::protocol::SubscribeMessage subscribeMessage = msg.subscribe_message();
      gatewayConnector->registerDataInterest(subscribeMessage.mime_type(), this);
    }
  }

  return 0;
}

void AndroidServiceHandler::onConnect(GatewayConnector *sender) {

}

void AndroidServiceHandler::onDisconnect(GatewayConnector *sender) {

}

void AndroidServiceHandler::onDataReceived(GatewayConnector *sender, std::string uri, std::string mimeType, std::vector<char> &data) {
  std::cout << "Sending subscribed data to device..." << std::endl;
  std::cout << "   URI: " << uri << ", Type: " << mimeType << std::endl << std::flush;;

  std::string dataString(data.begin(), data.end());
  ammmo::protocol::MessageWrapper msg;
  ammmo::protocol::DataMessage *dataMsg = msg.mutable_data_message();
  dataMsg->set_uri(uri);
  dataMsg->set_mime_type(mimeType);
  dataMsg->set_data(dataString);

  msg.set_type(ammmo::protocol::MessageWrapper_MessageType_DATA_MESSAGE);

  std::cout << "Sending Data Push message to connected plugin" << std::endl << std::flush;
  this->sendData(msg);
}

void AndroidServiceHandler::onAuthenticationResponse(GatewayConnector *sender, bool result) {
  std::cout << "Delegate: onAuthenticationResponse" << std::endl << std::flush;
  ammmo::protocol::MessageWrapper newMsg;
  newMsg.set_type(ammmo::protocol::MessageWrapper_MessageType_AUTHENTICATION_RESULT);
  newMsg.mutable_authentication_result()->set_result(result ? ammmo::protocol::AuthenticationResult_Status_SUCCESS : ammmo::protocol::AuthenticationResult_Status_SUCCESS);
  this->sendData(newMsg);
}

AndroidServiceHandler::~AndroidServiceHandler() {
  delete gatewayConnector;
}
<commit_msg>merging upstream<commit_after>#include "AndroidServiceHandler.h"
#include "protocol/AmmmoMessages.pb.h"

#include <iostream>

#include "ace/OS_NS_errno.h"

extern std::string gatewayAddress;
extern int gatewayPort;

int AndroidServiceHandler::open(void *ptr) {
  if(super::open(ptr) == -1) {
    return -1;

  }
  state = READING_SIZE;
  dataSize = 0;
  checksum = 0;
  collectedData = NULL;
  position = 0;

  gatewayConnector = new GatewayConnector(this);
}

int AndroidServiceHandler::handle_input(ACE_HANDLE fd) {
  //std::cout << "In handle_input" << std::endl << std::flush;
  int count = 0;

  if(state == READING_SIZE) {
    count = this->peer().recv_n(&dataSize, sizeof(dataSize));
    //std::cout << "SIZE Read " << count << " bytes" << std::endl << std::flush;
  } else if(state == READING_CHECKSUM) {
    count = this->peer().recv_n(&checksum, sizeof(checksum));
    //std::cout << "SUM Read " << count << " bytes" << std::endl << std::flush;
  } else if(state == READING_DATA) {
    count = this->peer().recv(collectedData + position, dataSize - position);
    //std::cout << "DATA Read " << count << " bytes" << std::endl << std::flush;
  } else {
    std::cout << "Invalid state!" << std::endl << std::flush;
  }

  if(count > 0) {
    if(state == READING_SIZE) {
      collectedData = new char[dataSize];
      position = 0;
      //std::cout << "Got data size (" << dataSize << ")" << std::endl << std::flush;
      state = READING_CHECKSUM;
    } else if(state == READING_CHECKSUM) {
      //std::cout << "Got data checksum (" << checksum << ")" << std::endl << std::flush;
      state = READING_DATA;
    } else if(state == READING_DATA) {
      //std::cout << "Got some data..." << std::endl << std::flush;
      position += count;
      if(position == dataSize) {
        //std::cout << "Got all the data... processing" << std::endl << std::flush;
        processData(collectedData, dataSize, checksum);
        //std::cout << "Processsing complete.  Deleting buffer." << std::endl << std::flush;
        delete[] collectedData;
        collectedData = NULL;
        dataSize = 0;
        position = 0;
        state = READING_SIZE;
      }
    }
  } else if(count == 0) {
    std::cout << "Connection closed." << std::endl << std::flush;
    return -1;
  } else if(count == -1 && ACE_OS::last_error () != EWOULDBLOCK) {
    std::cout << "Socket error occurred. (" << ACE_OS::last_error() << ")" << std::endl << std::flush;
    return -1;
  }
  //std::cout << "Leaving handle_input()" << std::endl << std::flush;
  return 0;
}

void AndroidServiceHandler::sendData(ammmo::protocol::MessageWrapper &msg) {
  /*Fixme: potential deadlock here
  unsigned int messageSize = msg.ByteSize();
  char *messageToSend = new char[messageSize];
  msg.SerializeToArray(messageToSend, messageSize);
  unsigned int messageChecksum = ACE::crc32(messageToSend, messageSize);

  ACE_Message_Block *messageSizeBlock = new ACE_Message_Block(sizeof(messageSize));
  messageSizeBlock->copy((char *) &messageSize, sizeof(messageSize));
  this->putq(messageSizeBlock);

  ACE_Message_Block *messageChecksumBlock = new ACE_Message_Block(sizeof(messageChecksum));
  messageChecksumBlock->copy((char *) &messageChecksum, sizeof(messageChecksum));
  this->putq(messageChecksumBlock);

  ACE_Message_Block *messageToSendBlock = new ACE_Message_Block(messageSize);
  messageToSendBlock->copy(messageToSend, messageSize);
  this->putq(messageToSendBlock);

  this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);*/

  unsigned int messageSize = msg.ByteSize();
  char *messageToSend = new char[messageSize];
  msg.SerializeToArray(messageToSend, messageSize);
  unsigned int messageChecksum = ACE::crc32(messageToSend, messageSize);

  this->peer().send_n(&messageSize, sizeof(messageSize));
  this->peer().send_n(&messageChecksum, sizeof(messageChecksum));
  this->peer().send_n(messageToSend, messageSize);
}

int AndroidServiceHandler::processData(char *data, unsigned int messageSize, unsigned int messageChecksum) {
  //Validate checksum
  unsigned int calculatedChecksum = ACE::crc32(data, messageSize);
  if(calculatedChecksum != messageChecksum) {
    std::cout << "Invalid checksum--  we've been sent bad data (perhaps a message size mismatch?)" << std::endl << std::flush;
    return -1;
  }

  //checksum is valid; parse the data
  ammmo::protocol::MessageWrapper msg;
  bool result = msg.ParseFromArray(data, messageSize);
  if(result == false) {
    std::cout << "MessageWrapper could not be deserialized." << std::endl;
    std::cout << "Client must have sent something that isn't a protocol buffer (or the wrong type)." << std::endl << std::flush;
    return -1;
  }
  std::cout << "Message Received: " << msg.DebugString() << std::endl << std::flush;

  if(msg.type() == ammmo::protocol::MessageWrapper_MessageType_AUTHENTICATION_MESSAGE) {
    std::cout << "Received Authentication Message..." << std::endl << std::flush;
    if(gatewayConnector != NULL) {
      ammmo::protocol::AuthenticationMessage authMessage = msg.authentication_message();
      gatewayConnector->associateDevice(authMessage.device_id(), authMessage.user_id(), authMessage.user_key());
    }
  } else if(msg.type() == ammmo::protocol::MessageWrapper_MessageType_DATA_MESSAGE) {
    std::cout << "Received Data Message..." << std::endl << std::flush;
    if(gatewayConnector != NULL) {
      ammmo::protocol::DataMessage dataMessage = msg.data_message();
      gatewayConnector->pushData(dataMessage.uri(), dataMessage.mime_type(), dataMessage.data());
    }
  } else if(msg.type() == ammmo::protocol::MessageWrapper_MessageType_SUBSCRIBE_MESSAGE) {
    std::cout << "Received Subscribe Message..." << std::endl << std::flush;
    if(gatewayConnector != NULL) {
      ammmo::protocol::SubscribeMessage subscribeMessage = msg.subscribe_message();
      gatewayConnector->registerDataInterest(subscribeMessage.mime_type(), this);
    }
  }

  return 0;
}

void AndroidServiceHandler::onConnect(GatewayConnector *sender) {

}

void AndroidServiceHandler::onDisconnect(GatewayConnector *sender) {

}

void AndroidServiceHandler::onDataReceived(GatewayConnector *sender, std::string uri, std::string mimeType, std::vector<char> &data) {
  std::cout << "Sending subscribed data to device..." << std::endl;
  std::cout << "   URI: " << uri << ", Type: " << mimeType << std::endl << std::flush;;

  std::string dataString(data.begin(), data.end());
  ammmo::protocol::MessageWrapper msg;
  ammmo::protocol::DataMessage *dataMsg = msg.mutable_data_message();
  dataMsg->set_uri(uri);
  dataMsg->set_mime_type(mimeType);
  dataMsg->set_data(dataString);

  msg.set_type(ammmo::protocol::MessageWrapper_MessageType_DATA_MESSAGE);

  std::cout << "Sending Data Push message to connected plugin" << std::endl << std::flush;
  this->sendData(msg);
}

void AndroidServiceHandler::onAuthenticationResponse(GatewayConnector *sender, bool result) {
  std::cout << "Delegate: onAuthenticationResponse" << std::endl << std::flush;
  ammmo::protocol::MessageWrapper newMsg;
  newMsg.set_type(ammmo::protocol::MessageWrapper_MessageType_AUTHENTICATION_RESULT);
  newMsg.mutable_authentication_result()->set_result(result ? ammmo::protocol::AuthenticationResult_Status_SUCCESS : ammmo::protocol::AuthenticationResult_Status_SUCCESS);
  this->sendData(newMsg);
}

AndroidServiceHandler::~AndroidServiceHandler() {
  delete gatewayConnector;
}
<|endoftext|>


<commit_before>/*
Copyright libCellML Contributors

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 "debug.h"

#include "libcellml/analyserequationast.h"
#include "libcellml/component.h"
#include "libcellml/generator.h"
#include "libcellml/model.h"
#include "libcellml/variable.h"

#ifdef NAN
#    undef NAN
#endif

namespace libcellml {

void printHistory(const History &history)
{
    for (const auto &h : history) {
        printHistoryEpoch(h);
    }

}

void printHistoryEpoch(const HistoryEpochPtr &historyEpoch)
{
    Debug() << "'" << historyEpoch->mSourceModel->name() << "' '" << historyEpoch->mName << "' '" << historyEpoch->mSourceUrl << "' -> '" << historyEpoch->mDestinationUrl << "'";
}

void printStack(const IndexStack &stack)
{
    bool first = true;
    Debug(false) << "[";
    for (const auto &iter : stack) {
        if (!first) {
            Debug(false) << ", ";
        }
        Debug(false) << iter;
        first = false;
    }
    Debug() << "]";
}

void printEquivalenceMap(const EquivalenceMap &map)
{
    Debug() << "Print out of equivalence map";
    for (const auto &iter : map) {
        auto key = iter.first;
        Debug(false) << "key: ";
        printStack(key);
        auto vector = iter.second;
        for (const auto &vectorIt : vector) {
            Debug(false) << "value: ";
            printStack(vectorIt);
        }
    }
}

void printEquivalenceMapWithModelInfo(const EquivalenceMap &map, const ModelPtr &model)
{
    for (const auto &iter : map) {
        auto key = iter.first;    Debug(false) << "key: ";
        printStackWithModelInfo(key, model);
        auto vector = iter.second;
        for (const auto &vectorIt : vector) {
            Debug(false) << "value: ";
            printStackWithModelInfo(vectorIt, model);
        }
    }
}

void printStackWithModelInfo(const IndexStack &stack, const ModelPtr &model)
{
    bool first = true;
    ComponentPtr entity;
    Debug(false) << "[";
    for (auto iter = stack.begin(); iter != stack.end(); ++iter) {
        if (!first) {
            Debug(false) << ", ";
        }
        auto next = iter;
        if (first) {
            entity = model->component(*iter);
            Debug(false) << entity->name();
        } else if (++next == stack.end()) {
            Debug(false) << entity->variable(*iter)->name();
        } else {
            entity = entity->component(*iter);
            Debug(false) << entity->name();
        }
        first = false;
    }
    Debug() << "]";
}

void printConnectionMap(const ConnectionMap &map)
{
    Debug() << "Print out of connection map";
    for (const auto &iter : map) {
        auto key = iter.first;
        auto value = iter.second;
        Debug() << "first: " << key->name();
        Debug() << "second: " << value->name();
    }
}

void printStringStringMap(const StringStringMap &map)
{
    Debug() << "Print out of string -> string map";
    for (const auto &iter : map) {
        Debug() << iter.first << ": " << iter.second;
    }
}

static const std::string SPACES = "  ";
static const std::string TRUNK = "  │";

struct AnalyserEquationAstTrunk
{
    AnalyserEquationAstTrunk *mPrev;
    std::string mStr;

    AnalyserEquationAstTrunk(AnalyserEquationAstTrunk *prev,
                             const std::string &str);
};

AnalyserEquationAstTrunk::AnalyserEquationAstTrunk(AnalyserEquationAstTrunk *prev,
                                                   const std::string &str)
    : mPrev(prev)
    , mStr(str)
{
}

void doPrintAst(AnalyserEquationAstTrunk *trunk)
{
    if (trunk == nullptr) {
        return;
    }

    doPrintAst(trunk->mPrev);

    if ((trunk->mPrev != nullptr) && (trunk->mPrev->mStr == SPACES)
        && ((trunk->mStr == SPACES) || (trunk->mStr == TRUNK))) {
        std::cout << " ";
    }

    std::cout << trunk->mStr;
}

std::string doPrintAst(const AnalyserEquationAstPtr &ast)
{
    std::string res;

    switch (ast->type()) {
        // Assignment.

    case AnalyserEquationAst::Type::ASSIGNMENT:
        res = "ASSIGNMENT";

        break;

        // Relational and logical operators.

    case AnalyserEquationAst::Type::EQ:
        res = "EQ";

        break;
    case AnalyserEquationAst::Type::NEQ:
        res = "NEQ";

        break;
    case AnalyserEquationAst::Type::LT:
        res = "LT";

        break;
    case AnalyserEquationAst::Type::LEQ:
        res = "LEQ";

        break;
    case AnalyserEquationAst::Type::GT:
        res = "GT";

        break;
    case AnalyserEquationAst::Type::GEQ:
        res = "LEQ";

        break;
    case AnalyserEquationAst::Type::AND:
        res = "AND";

        break;
    case AnalyserEquationAst::Type::OR:
        res = "OR";

        break;
    case AnalyserEquationAst::Type::XOR:
        res = "XOR";

        break;
    case AnalyserEquationAst::Type::NOT:
        res = "NOT";

        break;

        // Arithmetic operators.

    case AnalyserEquationAst::Type::PLUS:
        res = "PLUS";

        break;
    case AnalyserEquationAst::Type::MINUS:
        res = "MINUS";

        break;
    case AnalyserEquationAst::Type::TIMES:
        res = "TIMES";

        break;
    case AnalyserEquationAst::Type::DIVIDE:
        res = "DIVIDE";

        break;
    case AnalyserEquationAst::Type::POWER:
        res = "POWER";

        break;
    case AnalyserEquationAst::Type::ROOT:
        res = "ROOT";

        break;
    case AnalyserEquationAst::Type::ABS:
        res = "ABS";

        break;
    case AnalyserEquationAst::Type::EXP:
        res = "EXP";

        break;
    case AnalyserEquationAst::Type::LN:
        res = "LN";

        break;
    case AnalyserEquationAst::Type::LOG:
        res = "LOG";

        break;
    case AnalyserEquationAst::Type::CEILING:
        res = "CEILING";

        break;
    case AnalyserEquationAst::Type::FLOOR:
        res = "FLOOR";

        break;
    case AnalyserEquationAst::Type::MIN:
        res = "MIN";

        break;
    case AnalyserEquationAst::Type::MAX:
        res = "MAX";

        break;
    case AnalyserEquationAst::Type::REM:
        res = "REM";

        break;

        // Calculus elements.

    case AnalyserEquationAst::Type::DIFF:
        res = "DIFF";

        break;

        // Trigonometric operators.

    case AnalyserEquationAst::Type::SIN:
        res = "SIN";

        break;
    case AnalyserEquationAst::Type::COS:
        res = "COS";

        break;
    case AnalyserEquationAst::Type::TAN:
        res = "TAN";

        break;
    case AnalyserEquationAst::Type::SEC:
        res = "SEC";

        break;
    case AnalyserEquationAst::Type::CSC:
        res = "CSC";

        break;
    case AnalyserEquationAst::Type::COT:
        res = "COT";

        break;
    case AnalyserEquationAst::Type::SINH:
        res = "SINH";

        break;
    case AnalyserEquationAst::Type::COSH:
        res = "COSH";

        break;
    case AnalyserEquationAst::Type::TANH:
        res = "TANH";

        break;
    case AnalyserEquationAst::Type::SECH:
        res = "SECH";

        break;
    case AnalyserEquationAst::Type::CSCH:
        res = "CSCH";

        break;
    case AnalyserEquationAst::Type::COTH:
        res = "COTH";

        break;
    case AnalyserEquationAst::Type::ASIN:
        res = "ASIN";

        break;
    case AnalyserEquationAst::Type::ACOS:
        res = "ACOS";

        break;
    case AnalyserEquationAst::Type::ATAN:
        res = "ATAN";

        break;
    case AnalyserEquationAst::Type::ASEC:
        res = "ASEC";

        break;
    case AnalyserEquationAst::Type::ACSC:
        res = "ACSC";

        break;
    case AnalyserEquationAst::Type::ACOT:
        res = "ACOT";

        break;
    case AnalyserEquationAst::Type::ASINH:
        res = "ASINH";

        break;
    case AnalyserEquationAst::Type::ACOSH:
        res = "ACOSH";

        break;
    case AnalyserEquationAst::Type::ATANH:
        res = "ATANH";

        break;
    case AnalyserEquationAst::Type::ASECH:
        res = "ASECH";

        break;
    case AnalyserEquationAst::Type::ACSCH:
        res = "ACSCH";

        break;
    case AnalyserEquationAst::Type::ACOTH:
        res = "ACOTH";

        break;

        // Piecewise statement.

    case AnalyserEquationAst::Type::PIECEWISE:
        res = "PIECEWISE";

        break;
    case AnalyserEquationAst::Type::PIECE:
        res = "PIECE";

        break;
    case AnalyserEquationAst::Type::OTHERWISE:
        res = "OTHERWISE";

        break;

        // Token elements.

    case AnalyserEquationAst::Type::CI:
        res = ast->variable()->name();

        break;
    case AnalyserEquationAst::Type::CN:
        res = ast->value();

        break;

        // Qualifier elements.

    case AnalyserEquationAst::Type::DEGREE:
        res = "DEGREE";

        break;
    case AnalyserEquationAst::Type::LOGBASE:
        res = "LOGBASE";

        break;
    case AnalyserEquationAst::Type::BVAR:
        res = "BVAR";

        break;

        // Constants.

    case AnalyserEquationAst::Type::TRUE:
        res = "TRUE";

        break;
    case AnalyserEquationAst::Type::FALSE:
        res = "FALSE";

        break;
    case AnalyserEquationAst::Type::E:
        res = "E";

        break;
    case AnalyserEquationAst::Type::PI:
        res = "PI";

        break;
    case AnalyserEquationAst::Type::INF:
        res = "INF";

        break;
    case AnalyserEquationAst::Type::NAN:
        res = "NAN";

        break;
    }

    return res;
}

void doPrintAst(const AnalyserEquationAstPtr &ast,
                AnalyserEquationAstTrunk *prevTrunk, bool isLeft)
{
    if (ast == nullptr) {
        return;
    }

    std::string prevStr = SPACES;
    AnalyserEquationAstTrunk trunk(prevTrunk, prevStr);

    doPrintAst(ast->leftChild(), &trunk, true);

    if (prevTrunk == nullptr) {
        trunk.mStr = "──";
    } else if (isLeft) {
        trunk.mStr = "╭──";
        prevStr = TRUNK;
    } else {
        trunk.mStr = "╰──";
        prevTrunk->mStr = prevStr;
    }

    doPrintAst(&trunk);

    std::cout << doPrintAst(ast) << std::endl;

    if (prevTrunk != nullptr) {
        prevTrunk->mStr = prevStr;
    }

    trunk.mStr = TRUNK;

    doPrintAst(ast->rightChild(), &trunk, false);
}

void printAst(const AnalyserEquationAstPtr &ast)
{
    doPrintAst(ast, nullptr, false);
}

void printImportLibrary(const ImportLibrary &importlibrary)
{
    Debug() << " == Import library ==";
    for ( const auto &entry : importlibrary) {
        std::string name = "(null)";
        if (entry.second != nullptr) {
            name = entry.second->name();
        }
        Debug() << entry.first << " - " << name;
    }
    Debug() << " == ";
}

} // namespace libcellml
<commit_msg>Remove space in printImportLibrary for loop.<commit_after>/*
Copyright libCellML Contributors

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 "debug.h"

#include "libcellml/analyserequationast.h"
#include "libcellml/component.h"
#include "libcellml/generator.h"
#include "libcellml/model.h"
#include "libcellml/variable.h"

#ifdef NAN
#    undef NAN
#endif

namespace libcellml {

void printHistory(const History &history)
{
    for (const auto &h : history) {
        printHistoryEpoch(h);
    }

}

void printHistoryEpoch(const HistoryEpochPtr &historyEpoch)
{
    Debug() << "'" << historyEpoch->mSourceModel->name() << "' '" << historyEpoch->mName << "' '" << historyEpoch->mSourceUrl << "' -> '" << historyEpoch->mDestinationUrl << "'";
}

void printStack(const IndexStack &stack)
{
    bool first = true;
    Debug(false) << "[";
    for (const auto &iter : stack) {
        if (!first) {
            Debug(false) << ", ";
        }
        Debug(false) << iter;
        first = false;
    }
    Debug() << "]";
}

void printEquivalenceMap(const EquivalenceMap &map)
{
    Debug() << "Print out of equivalence map";
    for (const auto &iter : map) {
        auto key = iter.first;
        Debug(false) << "key: ";
        printStack(key);
        auto vector = iter.second;
        for (const auto &vectorIt : vector) {
            Debug(false) << "value: ";
            printStack(vectorIt);
        }
    }
}

void printEquivalenceMapWithModelInfo(const EquivalenceMap &map, const ModelPtr &model)
{
    for (const auto &iter : map) {
        auto key = iter.first;    Debug(false) << "key: ";
        printStackWithModelInfo(key, model);
        auto vector = iter.second;
        for (const auto &vectorIt : vector) {
            Debug(false) << "value: ";
            printStackWithModelInfo(vectorIt, model);
        }
    }
}

void printStackWithModelInfo(const IndexStack &stack, const ModelPtr &model)
{
    bool first = true;
    ComponentPtr entity;
    Debug(false) << "[";
    for (auto iter = stack.begin(); iter != stack.end(); ++iter) {
        if (!first) {
            Debug(false) << ", ";
        }
        auto next = iter;
        if (first) {
            entity = model->component(*iter);
            Debug(false) << entity->name();
        } else if (++next == stack.end()) {
            Debug(false) << entity->variable(*iter)->name();
        } else {
            entity = entity->component(*iter);
            Debug(false) << entity->name();
        }
        first = false;
    }
    Debug() << "]";
}

void printConnectionMap(const ConnectionMap &map)
{
    Debug() << "Print out of connection map";
    for (const auto &iter : map) {
        auto key = iter.first;
        auto value = iter.second;
        Debug() << "first: " << key->name();
        Debug() << "second: " << value->name();
    }
}

void printStringStringMap(const StringStringMap &map)
{
    Debug() << "Print out of string -> string map";
    for (const auto &iter : map) {
        Debug() << iter.first << ": " << iter.second;
    }
}

static const std::string SPACES = "  ";
static const std::string TRUNK = "  │";

struct AnalyserEquationAstTrunk
{
    AnalyserEquationAstTrunk *mPrev;
    std::string mStr;

    AnalyserEquationAstTrunk(AnalyserEquationAstTrunk *prev,
                             const std::string &str);
};

AnalyserEquationAstTrunk::AnalyserEquationAstTrunk(AnalyserEquationAstTrunk *prev,
                                                   const std::string &str)
    : mPrev(prev)
    , mStr(str)
{
}

void doPrintAst(AnalyserEquationAstTrunk *trunk)
{
    if (trunk == nullptr) {
        return;
    }

    doPrintAst(trunk->mPrev);

    if ((trunk->mPrev != nullptr) && (trunk->mPrev->mStr == SPACES)
        && ((trunk->mStr == SPACES) || (trunk->mStr == TRUNK))) {
        std::cout << " ";
    }

    std::cout << trunk->mStr;
}

std::string doPrintAst(const AnalyserEquationAstPtr &ast)
{
    std::string res;

    switch (ast->type()) {
        // Assignment.

    case AnalyserEquationAst::Type::ASSIGNMENT:
        res = "ASSIGNMENT";

        break;

        // Relational and logical operators.

    case AnalyserEquationAst::Type::EQ:
        res = "EQ";

        break;
    case AnalyserEquationAst::Type::NEQ:
        res = "NEQ";

        break;
    case AnalyserEquationAst::Type::LT:
        res = "LT";

        break;
    case AnalyserEquationAst::Type::LEQ:
        res = "LEQ";

        break;
    case AnalyserEquationAst::Type::GT:
        res = "GT";

        break;
    case AnalyserEquationAst::Type::GEQ:
        res = "LEQ";

        break;
    case AnalyserEquationAst::Type::AND:
        res = "AND";

        break;
    case AnalyserEquationAst::Type::OR:
        res = "OR";

        break;
    case AnalyserEquationAst::Type::XOR:
        res = "XOR";

        break;
    case AnalyserEquationAst::Type::NOT:
        res = "NOT";

        break;

        // Arithmetic operators.

    case AnalyserEquationAst::Type::PLUS:
        res = "PLUS";

        break;
    case AnalyserEquationAst::Type::MINUS:
        res = "MINUS";

        break;
    case AnalyserEquationAst::Type::TIMES:
        res = "TIMES";

        break;
    case AnalyserEquationAst::Type::DIVIDE:
        res = "DIVIDE";

        break;
    case AnalyserEquationAst::Type::POWER:
        res = "POWER";

        break;
    case AnalyserEquationAst::Type::ROOT:
        res = "ROOT";

        break;
    case AnalyserEquationAst::Type::ABS:
        res = "ABS";

        break;
    case AnalyserEquationAst::Type::EXP:
        res = "EXP";

        break;
    case AnalyserEquationAst::Type::LN:
        res = "LN";

        break;
    case AnalyserEquationAst::Type::LOG:
        res = "LOG";

        break;
    case AnalyserEquationAst::Type::CEILING:
        res = "CEILING";

        break;
    case AnalyserEquationAst::Type::FLOOR:
        res = "FLOOR";

        break;
    case AnalyserEquationAst::Type::MIN:
        res = "MIN";

        break;
    case AnalyserEquationAst::Type::MAX:
        res = "MAX";

        break;
    case AnalyserEquationAst::Type::REM:
        res = "REM";

        break;

        // Calculus elements.

    case AnalyserEquationAst::Type::DIFF:
        res = "DIFF";

        break;

        // Trigonometric operators.

    case AnalyserEquationAst::Type::SIN:
        res = "SIN";

        break;
    case AnalyserEquationAst::Type::COS:
        res = "COS";

        break;
    case AnalyserEquationAst::Type::TAN:
        res = "TAN";

        break;
    case AnalyserEquationAst::Type::SEC:
        res = "SEC";

        break;
    case AnalyserEquationAst::Type::CSC:
        res = "CSC";

        break;
    case AnalyserEquationAst::Type::COT:
        res = "COT";

        break;
    case AnalyserEquationAst::Type::SINH:
        res = "SINH";

        break;
    case AnalyserEquationAst::Type::COSH:
        res = "COSH";

        break;
    case AnalyserEquationAst::Type::TANH:
        res = "TANH";

        break;
    case AnalyserEquationAst::Type::SECH:
        res = "SECH";

        break;
    case AnalyserEquationAst::Type::CSCH:
        res = "CSCH";

        break;
    case AnalyserEquationAst::Type::COTH:
        res = "COTH";

        break;
    case AnalyserEquationAst::Type::ASIN:
        res = "ASIN";

        break;
    case AnalyserEquationAst::Type::ACOS:
        res = "ACOS";

        break;
    case AnalyserEquationAst::Type::ATAN:
        res = "ATAN";

        break;
    case AnalyserEquationAst::Type::ASEC:
        res = "ASEC";

        break;
    case AnalyserEquationAst::Type::ACSC:
        res = "ACSC";

        break;
    case AnalyserEquationAst::Type::ACOT:
        res = "ACOT";

        break;
    case AnalyserEquationAst::Type::ASINH:
        res = "ASINH";

        break;
    case AnalyserEquationAst::Type::ACOSH:
        res = "ACOSH";

        break;
    case AnalyserEquationAst::Type::ATANH:
        res = "ATANH";

        break;
    case AnalyserEquationAst::Type::ASECH:
        res = "ASECH";

        break;
    case AnalyserEquationAst::Type::ACSCH:
        res = "ACSCH";

        break;
    case AnalyserEquationAst::Type::ACOTH:
        res = "ACOTH";

        break;

        // Piecewise statement.

    case AnalyserEquationAst::Type::PIECEWISE:
        res = "PIECEWISE";

        break;
    case AnalyserEquationAst::Type::PIECE:
        res = "PIECE";

        break;
    case AnalyserEquationAst::Type::OTHERWISE:
        res = "OTHERWISE";

        break;

        // Token elements.

    case AnalyserEquationAst::Type::CI:
        res = ast->variable()->name();

        break;
    case AnalyserEquationAst::Type::CN:
        res = ast->value();

        break;

        // Qualifier elements.

    case AnalyserEquationAst::Type::DEGREE:
        res = "DEGREE";

        break;
    case AnalyserEquationAst::Type::LOGBASE:
        res = "LOGBASE";

        break;
    case AnalyserEquationAst::Type::BVAR:
        res = "BVAR";

        break;

        // Constants.

    case AnalyserEquationAst::Type::TRUE:
        res = "TRUE";

        break;
    case AnalyserEquationAst::Type::FALSE:
        res = "FALSE";

        break;
    case AnalyserEquationAst::Type::E:
        res = "E";

        break;
    case AnalyserEquationAst::Type::PI:
        res = "PI";

        break;
    case AnalyserEquationAst::Type::INF:
        res = "INF";

        break;
    case AnalyserEquationAst::Type::NAN:
        res = "NAN";

        break;
    }

    return res;
}

void doPrintAst(const AnalyserEquationAstPtr &ast,
                AnalyserEquationAstTrunk *prevTrunk, bool isLeft)
{
    if (ast == nullptr) {
        return;
    }

    std::string prevStr = SPACES;
    AnalyserEquationAstTrunk trunk(prevTrunk, prevStr);

    doPrintAst(ast->leftChild(), &trunk, true);

    if (prevTrunk == nullptr) {
        trunk.mStr = "──";
    } else if (isLeft) {
        trunk.mStr = "╭──";
        prevStr = TRUNK;
    } else {
        trunk.mStr = "╰──";
        prevTrunk->mStr = prevStr;
    }

    doPrintAst(&trunk);

    std::cout << doPrintAst(ast) << std::endl;

    if (prevTrunk != nullptr) {
        prevTrunk->mStr = prevStr;
    }

    trunk.mStr = TRUNK;

    doPrintAst(ast->rightChild(), &trunk, false);
}

void printAst(const AnalyserEquationAstPtr &ast)
{
    doPrintAst(ast, nullptr, false);
}

void printImportLibrary(const ImportLibrary &importlibrary)
{
    Debug() << " == Import library ==";
    for (const auto &entry : importlibrary) {
        std::string name = "(null)";
        if (entry.second != nullptr) {
            name = entry.second->name();
        }
        Debug() << entry.first << " - " << name;
    }
    Debug() << " == ";
}

} // namespace libcellml
<|endoftext|>