<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Baldur Karlsson
 * Copyright (c) 2014 Crytek
 *
 * 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 "os/os_specific.h"
#include "api/app/renderdoc_app.h"
#include "api/replay/capture_options.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
#include <libgen.h>

#include "serialise/string_utils.h"

static vector<Process::EnvironmentModification> &GetEnvModifications()
{
	static vector<Process::EnvironmentModification> envCallbacks;
	return envCallbacks;
}

static map<string, string> EnvStringToEnvMap(const char **envstring)
{
	map<string, string> ret;

	const char **e = envstring;

	while(*e)
	{
		const char *equals = strchr(*e, '=');

		string name;
		string value;

		name.assign(*e, equals);
		value = equals+1;

		ret[name] = value;

		e++;
	}

	return ret;
}

void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif)
{
	GetEnvModifications().push_back(modif);
}

// on linux we apply environment changes before launching the program, as
// there is no support for injecting/loading renderdoc into a running program
// in any way, and we also have some environment changes that we *have* to make
// for correct hooking (LD_LIBRARY_PATH/LD_PRELOAD)
void Process::ApplyEnvironmentModification()
{
}

static pid_t RunProcess(const char *app, const char *workingDir, const char *cmdLine, char *const *envp)
{
	if(!app) return (pid_t)0;

	int argc = 0;
	char *emptyargv[] = { NULL };
	char **argv = emptyargv;

	const char *c = cmdLine;

	// parse command line into argv[], similar to how bash would
	if(cmdLine)
	{
		argc = 1;

		// get a rough upper bound on the number of arguments
		while(*c)
		{
			if(*c == ' ' || *c == '\t') argc++;
			c++;
		}

		argv = new char*[argc+2];

		c = cmdLine;

		string a;

		argc = 0; // current argument we're fetching

		// argv[0] is the application name, by convention
		size_t len = strlen(app)+1;
		argv[argc] = new char[len];
		strcpy(argv[argc], app);

		argc++;

		bool dquot = false, squot = false; // are we inside ''s or ""s
		while(*c)
		{
			if(!dquot && !squot && (*c == ' ' || *c == '\t'))
			{
				if(!a.empty())
				{
					// if we've fetched some number of non-space characters
					argv[argc] = new char[a.length()+1];
					memcpy(argv[argc], a.c_str(), a.length()+1);
					argc++;
				}

				a = "";
			}
			else if(!dquot && *c == '"')
			{
				dquot = true;
			}
			else if(!squot && *c == '\'')
			{
				squot = true;
			}
			else if(dquot && *c == '"')
			{
				dquot = false;
			}
			else if(squot && *c == '\'')
			{
				squot = false;
			}
			else if(squot)
			{
				// single quotes don't escape, just copy literally until we leave single quote mode
				a.push_back(*c);
			}
			else if(dquot)
			{
				// handle escaping
				if(*c == '\\')
				{
					c++;
					if(*c)
					{
						a.push_back(*c);
					}
					else
					{
						RDCERR("Malformed command line:\n%s", cmdLine);
						return 0;
					}
				}
				else
				{
					a.push_back(*c);
				}
			}
			else
			{
				a.push_back(*c);
			}

			c++;
		}

		if(!a.empty())
		{
			// if we've fetched some number of non-space characters
			argv[argc] = new char[a.length()+1];
			memcpy(argv[argc], a.c_str(), a.length()+1);
			argc++;
		}

		argv[argc] = NULL;

		if(squot || dquot)
		{
			RDCERR("Malformed command line\n%s", cmdLine);
			return 0;
		}
	}

	pid_t childPid = fork();
	if(childPid == 0)
	{
		if(workingDir)
		{
			chdir(workingDir);
		}
		else
		{
			string exedir = app;
			chdir(dirname((char *)exedir.c_str()));
		}

		execve(app, argv, envp);
		exit(0);
	}

	char **argv_delete = argv;

	if(argv != emptyargv)
	{
		while(*argv)
		{
			delete[] *argv;
			argv++;
		}

		delete[] argv_delete;
	}

	return childPid;
}

uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	RDCUNIMPLEMENTED("Injecting into already running processes on linux");
	return 0;
}

uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const char *cmdLine)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	return (uint32_t)RunProcess(app, workingDir, cmdLine, environ);
}

uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine,
                                             const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	// turn environment string to a UTF-8 map
	map<string, string> env = EnvStringToEnvMap((const char **)environ);
	vector<EnvironmentModification> &modifications = GetEnvModifications();

	string libpath;
	{
		FileIO::GetExecutableFilename(libpath);
		libpath = dirname(libpath);
	}

	string optstr;
	{
		optstr.reserve(sizeof(CaptureOptions)*2+1);
		byte *b = (byte *)opts;
		for(size_t i=0; i < sizeof(CaptureOptions); i++)
		{
			optstr.push_back(char( 'a' + ((b[i] >> 4)&0xf) ));
			optstr.push_back(char( 'a' + ((b[i]     )&0xf) ));
		}
	}

	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_LIBRARY_PATH", libpath.c_str()));
	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_PRELOAD", "librenderdoc.so"));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_LOGFILE", logfile));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_CAPTUREOPTS", optstr.c_str()));

	for(size_t i=0; i < modifications.size(); i++)
	{
		EnvironmentModification &m = modifications[i];

		string value = env[m.name];

		switch(m.type)
		{
			case eEnvModification_Replace:
				value = m.value;
				break;
			case eEnvModification_Append:
				value += m.value;
				break;
			case eEnvModification_AppendColon:
				if(!value.empty())
					value += ":";
				value += m.value;
				break;
			case eEnvModification_AppendPlatform:
			case eEnvModification_AppendSemiColon:
				if(!value.empty())
					value += ";";
				value += m.value;
				break;
			case eEnvModification_Prepend:
				value = m.value + value;
				break;
			case eEnvModification_PrependColon:
				if(!value.empty())
					value = m.value + ":" + value;
				else
					value = m.value;
				break;
			case eEnvModification_PrependPlatform:
			case eEnvModification_PrependSemiColon:
				if(!value.empty())
					value = m.value + ";" + value;
				else
					value = m.value;
				break;
			default:
				RDCERR("Unexpected environment modification type");
		}
	}

	char **envp = new char *[env.size()+1];
	envp[env.size()] = NULL;

	int i=0;
	for(auto it=env.begin(); it != env.end(); it++)
	{
		string envline = it->first + "=" + it->second;
		envp[i] = new char[envline.size()+1];
		memcpy(envp[i], envline.c_str(), envline.size()+1);
		i++;
	}

	pid_t childPid = RunProcess(app, workingDir, cmdLine, envp);

	int ret = 0;

	if(childPid != (pid_t)0)
	{
		// wait for child to have /proc/<pid> and read out tcp socket
		usleep(1000);

		string procfile = StringFormat::Fmt("/proc/%d/net/tcp", (int)childPid);

		// try for a little while for the /proc entry to appear
		for(int retry=0; retry < 10; retry++)
		{
			// back-off for each retry
			usleep(1000 + 500 * retry);

			FILE *f =	FileIO::fopen(procfile.c_str(), "r");

			if(f == NULL)
			{
				// try again in a bit
				continue;
			}

			// read through the proc file to check for an open listen socket
			while(ret == 0 && !feof(f))
			{
				const size_t sz = 512;
				char line[sz];line[sz-1] = 0;
				fgets(line, sz-1, f);

				int socketnum = 0, hexip = 0, hexport = 0;
				int num = sscanf(line, " %d: %x:%x", &socketnum, &hexip, &hexport);

				// find open listen socket on 0.0.0.0:port
				if(num == 3 && hexip == 0 &&
						hexport >= RenderDoc_FirstCaptureNetworkPort &&
						hexport <= RenderDoc_LastCaptureNetworkPort)
				{
					ret = hexport;
				}
			}

			FileIO::fclose(f);
		}

		if(waitForExit)
		{
			int dummy = 0;
			waitpid(childPid, &dummy, 0);
		}
	}

	char **envp_delete = envp;

	while(*envp)
	{
		delete[] *envp;
		envp++;
	}

	delete[] envp_delete;

	return ret;
}

void Process::StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions *opts)
{
	RDCUNIMPLEMENTED("Global hooking of all processes on linux");
}

void *Process::LoadModule(const char *module)
{
	return dlopen(module, RTLD_NOW);
}

void *Process::GetFunctionAddress(void *module, const char *function)
{
	if(module == NULL) return NULL;

	return dlsym(module, function);
}

uint32_t Process::GetCurrentPID()
{
	return (uint32_t)getpid();
}
<commit_msg>Linux platform separator is colon, not semi-colon<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Baldur Karlsson
 * Copyright (c) 2014 Crytek
 *
 * 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 "os/os_specific.h"
#include "api/app/renderdoc_app.h"
#include "api/replay/capture_options.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
#include <libgen.h>

#include "serialise/string_utils.h"

static vector<Process::EnvironmentModification> &GetEnvModifications()
{
	static vector<Process::EnvironmentModification> envCallbacks;
	return envCallbacks;
}

static map<string, string> EnvStringToEnvMap(const char **envstring)
{
	map<string, string> ret;

	const char **e = envstring;

	while(*e)
	{
		const char *equals = strchr(*e, '=');

		string name;
		string value;

		name.assign(*e, equals);
		value = equals+1;

		ret[name] = value;

		e++;
	}

	return ret;
}

void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif)
{
	GetEnvModifications().push_back(modif);
}

// on linux we apply environment changes before launching the program, as
// there is no support for injecting/loading renderdoc into a running program
// in any way, and we also have some environment changes that we *have* to make
// for correct hooking (LD_LIBRARY_PATH/LD_PRELOAD)
void Process::ApplyEnvironmentModification()
{
}

static pid_t RunProcess(const char *app, const char *workingDir, const char *cmdLine, char *const *envp)
{
	if(!app) return (pid_t)0;

	int argc = 0;
	char *emptyargv[] = { NULL };
	char **argv = emptyargv;

	const char *c = cmdLine;

	// parse command line into argv[], similar to how bash would
	if(cmdLine)
	{
		argc = 1;

		// get a rough upper bound on the number of arguments
		while(*c)
		{
			if(*c == ' ' || *c == '\t') argc++;
			c++;
		}

		argv = new char*[argc+2];

		c = cmdLine;

		string a;

		argc = 0; // current argument we're fetching

		// argv[0] is the application name, by convention
		size_t len = strlen(app)+1;
		argv[argc] = new char[len];
		strcpy(argv[argc], app);

		argc++;

		bool dquot = false, squot = false; // are we inside ''s or ""s
		while(*c)
		{
			if(!dquot && !squot && (*c == ' ' || *c == '\t'))
			{
				if(!a.empty())
				{
					// if we've fetched some number of non-space characters
					argv[argc] = new char[a.length()+1];
					memcpy(argv[argc], a.c_str(), a.length()+1);
					argc++;
				}

				a = "";
			}
			else if(!dquot && *c == '"')
			{
				dquot = true;
			}
			else if(!squot && *c == '\'')
			{
				squot = true;
			}
			else if(dquot && *c == '"')
			{
				dquot = false;
			}
			else if(squot && *c == '\'')
			{
				squot = false;
			}
			else if(squot)
			{
				// single quotes don't escape, just copy literally until we leave single quote mode
				a.push_back(*c);
			}
			else if(dquot)
			{
				// handle escaping
				if(*c == '\\')
				{
					c++;
					if(*c)
					{
						a.push_back(*c);
					}
					else
					{
						RDCERR("Malformed command line:\n%s", cmdLine);
						return 0;
					}
				}
				else
				{
					a.push_back(*c);
				}
			}
			else
			{
				a.push_back(*c);
			}

			c++;
		}

		if(!a.empty())
		{
			// if we've fetched some number of non-space characters
			argv[argc] = new char[a.length()+1];
			memcpy(argv[argc], a.c_str(), a.length()+1);
			argc++;
		}

		argv[argc] = NULL;

		if(squot || dquot)
		{
			RDCERR("Malformed command line\n%s", cmdLine);
			return 0;
		}
	}

	pid_t childPid = fork();
	if(childPid == 0)
	{
		if(workingDir)
		{
			chdir(workingDir);
		}
		else
		{
			string exedir = app;
			chdir(dirname((char *)exedir.c_str()));
		}

		execve(app, argv, envp);
		exit(0);
	}

	char **argv_delete = argv;

	if(argv != emptyargv)
	{
		while(*argv)
		{
			delete[] *argv;
			argv++;
		}

		delete[] argv_delete;
	}

	return childPid;
}

uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	RDCUNIMPLEMENTED("Injecting into already running processes on linux");
	return 0;
}

uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const char *cmdLine)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	return (uint32_t)RunProcess(app, workingDir, cmdLine, environ);
}

uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine,
                                             const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	// turn environment string to a UTF-8 map
	map<string, string> env = EnvStringToEnvMap((const char **)environ);
	vector<EnvironmentModification> &modifications = GetEnvModifications();

	string libpath;
	{
		FileIO::GetExecutableFilename(libpath);
		libpath = dirname(libpath);
	}

	string optstr;
	{
		optstr.reserve(sizeof(CaptureOptions)*2+1);
		byte *b = (byte *)opts;
		for(size_t i=0; i < sizeof(CaptureOptions); i++)
		{
			optstr.push_back(char( 'a' + ((b[i] >> 4)&0xf) ));
			optstr.push_back(char( 'a' + ((b[i]     )&0xf) ));
		}
	}

	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_LIBRARY_PATH", libpath.c_str()));
	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_PRELOAD", "librenderdoc.so"));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_LOGFILE", logfile));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_CAPTUREOPTS", optstr.c_str()));

	for(size_t i=0; i < modifications.size(); i++)
	{
		EnvironmentModification &m = modifications[i];

		string value = env[m.name];

		switch(m.type)
		{
			case eEnvModification_Replace:
				value = m.value;
				break;
			case eEnvModification_Append:
				value += m.value;
				break;
			case eEnvModification_AppendPlatform:
			case eEnvModification_AppendColon:
				if(!value.empty())
					value += ":";
				value += m.value;
				break;
			case eEnvModification_AppendSemiColon:
				if(!value.empty())
					value += ";";
				value += m.value;
				break;
			case eEnvModification_Prepend:
				value = m.value + value;
				break;
			case eEnvModification_PrependColon:
				if(!value.empty())
					value = m.value + ":" + value;
				else
					value = m.value;
				break;
			case eEnvModification_PrependPlatform:
			case eEnvModification_PrependSemiColon:
				if(!value.empty())
					value = m.value + ";" + value;
				else
					value = m.value;
				break;
			default:
				RDCERR("Unexpected environment modification type");
		}
	}

	char **envp = new char *[env.size()+1];
	envp[env.size()] = NULL;

	int i=0;
	for(auto it=env.begin(); it != env.end(); it++)
	{
		string envline = it->first + "=" + it->second;
		envp[i] = new char[envline.size()+1];
		memcpy(envp[i], envline.c_str(), envline.size()+1);
		i++;
	}

	pid_t childPid = RunProcess(app, workingDir, cmdLine, envp);

	int ret = 0;

	if(childPid != (pid_t)0)
	{
		// wait for child to have /proc/<pid> and read out tcp socket
		usleep(1000);

		string procfile = StringFormat::Fmt("/proc/%d/net/tcp", (int)childPid);

		// try for a little while for the /proc entry to appear
		for(int retry=0; retry < 10; retry++)
		{
			// back-off for each retry
			usleep(1000 + 500 * retry);

			FILE *f =	FileIO::fopen(procfile.c_str(), "r");

			if(f == NULL)
			{
				// try again in a bit
				continue;
			}

			// read through the proc file to check for an open listen socket
			while(ret == 0 && !feof(f))
			{
				const size_t sz = 512;
				char line[sz];line[sz-1] = 0;
				fgets(line, sz-1, f);

				int socketnum = 0, hexip = 0, hexport = 0;
				int num = sscanf(line, " %d: %x:%x", &socketnum, &hexip, &hexport);

				// find open listen socket on 0.0.0.0:port
				if(num == 3 && hexip == 0 &&
						hexport >= RenderDoc_FirstCaptureNetworkPort &&
						hexport <= RenderDoc_LastCaptureNetworkPort)
				{
					ret = hexport;
				}
			}

			FileIO::fclose(f);
		}

		if(waitForExit)
		{
			int dummy = 0;
			waitpid(childPid, &dummy, 0);
		}
	}

	char **envp_delete = envp;

	while(*envp)
	{
		delete[] *envp;
		envp++;
	}

	delete[] envp_delete;

	return ret;
}

void Process::StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions *opts)
{
	RDCUNIMPLEMENTED("Global hooking of all processes on linux");
}

void *Process::LoadModule(const char *module)
{
	return dlopen(module, RTLD_NOW);
}

void *Process::GetFunctionAddress(void *module, const char *function)
{
	if(module == NULL) return NULL;

	return dlsym(module, function);
}

uint32_t Process::GetCurrentPID()
{
	return (uint32_t)getpid();
}
<|endoftext|>


<commit_before>#include "networkmanager.h"
#include "../networkhelper.h"
#include "../log/logger.h"
#include "../settings.h"

#include "tcpsocket.h"
#include "udpsocket.h"

#include <QJsonDocument>
#include <QPointer>
#include <QTcpServer>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QStringList>
#include <QHash>
#include <QMutex>
#include <QReadWriteLock>
#include <QTimer>
#include <QDebug>

LOGGER(NetworkManager)

class NetworkManager::Private : public QObject
{
    Q_OBJECT

public:
    Private(NetworkManager* q)
    : q(q)
    {
        connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
    }

    NetworkManager* q;

    // Properties
    QMutex mutex;
    QHash<QString, QObject*> objectHash;
    QHash<QString, QAbstractSocket*> socketHash;

    QTimer timer;
    QPointer<QUdpSocket> socket;
    QPointer<Settings> settings;

    quint16 localPort;

    // Functions
    QAbstractSocket* createSocket(NetworkManager::SocketType socketType);

    void updateSocket();
    void updateTimer();
    void processDatagram(const QByteArray& datagram, const QHostAddress& host, quint16 port);

public slots:
    void socketDestroyed(QObject* obj);
    void responseChanged();
    void timeout();
    void onDatagramReady();
};

QAbstractSocket *NetworkManager::Private::createSocket(NetworkManager::SocketType socketType)
{
    QAbstractSocket* socket = NULL;

    switch(socketType) {
    case TcpSocket:
        socket = new ::TcpSocket;
        break;

    case UdpSocket:
        socket = new ::UdpSocket;
        break;

    case UtpSocket:
        //socket = new UtpSocket;
        break;

    default:
        break;
    }

    if (socket) {
        connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(socketDestroyed(QObject*)));
    }

    return socket;
}

void NetworkManager::Private::socketDestroyed(QObject *obj)
{
    QString hostname = objectHash.key(obj);
    if (hostname.isEmpty())
        return;

    objectHash.remove(hostname);
    socketHash.remove(hostname);
}

void NetworkManager::Private::updateSocket()
{
    if (!socket.isNull())
        socket->deleteLater();

    QString keepaliveAddress = settings->config()->keepaliveAddress();
    RemoteHost remote = NetworkHelper::remoteHost(keepaliveAddress);
    if (!remote.isValid())
        return;

    localPort = remote.port;

    socket = qobject_cast<QUdpSocket*>( q->createConnection(NetworkManager::UdpSocket) );
    connect(socket.data(), SIGNAL(readyRead()), this, SLOT(onDatagramReady()));
    if (!socket->bind(remote.port)) {
        LOG_INFO(QString("Unable to bind port %1: %2").arg(remote.port).arg(socket->errorString()));
    }
}

void NetworkManager::Private::updateTimer()
{
    int interval = settings->config()->keepaliveSchedule()->interval();
    if (interval < 1000) {
        LOG_INFO("Keepalive interval < 1 sec will not be accepted.");
        return;
    } else {
        LOG_INFO(QString("Keepalive set to %1 sec.").arg(interval/1000));
    }

    timer.setInterval(interval);
    timer.start();
}

void NetworkManager::Private::processDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)
{
    QString hostAndPort = QString("%1:%2").arg(host.toString()).arg(port);
    if (settings->config()->keepaliveAddress() == hostAndPort) {
        // Master server
        QJsonParseError error;
        QJsonDocument document = QJsonDocument::fromJson(datagram, &error);

        if (error.error == QJsonParseError::NoError) {
            // TODO: Read data
        } else {
            LOG_ERROR(QString("Invalid JSon from master server: %1").arg(error.errorString()));
        }
    } else {
        // TODO: Process incoming data
    }
}

void NetworkManager::Private::responseChanged()
{
    updateSocket();
    updateTimer();

    // Send the first timeout now
    timeout();
}

void NetworkManager::Private::timeout()
{
    RemoteHost remote = NetworkHelper::remoteHost(settings->config()->keepaliveAddress());
    if (!remote.isValid()) {
        LOG_INFO("Invalid keepalive host");
        return;
    }

    QString sessionId = settings->sessionId();
    if (sessionId.isEmpty()) {
        LOG_INFO("Empty session id");
        return;
    }

    QStringList srcIp;
    srcIp.append( NetworkHelper::localIpAddress().toString() );

    QVariantMap map;
    map.insert("type", "keepalive");
    map.insert("session_id", sessionId);
    map.insert("src_ip", srcIp);
    map.insert("src_port", localPort);

    QByteArray data = QJsonDocument::fromVariant(map).toJson();
    socket->writeDatagram(data, QHostAddress(remote.host), remote.port);

    LOG_INFO("Alive packet sent");
}

void NetworkManager::Private::onDatagramReady()
{
    while (socket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(socket->pendingDatagramSize());

        QHostAddress host;
        quint16 port;
        socket->readDatagram(datagram.data(), datagram.size(), &host, &port);

        // Process the datagram
        processDatagram(datagram, host, port);
    }
}

NetworkManager::NetworkManager(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}

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

bool NetworkManager::init(Settings *settings)
{
    connect(settings->config(), SIGNAL(responseChanged()), d, SLOT(responseChanged()));

    d->settings = settings;
    d->responseChanged();
}

void NetworkManager::setRunning(bool running)
{
    if (isRunning() == running)
        return;

    if ( !running )
        d->timer.stop();
    else
        d->updateTimer();
}

bool NetworkManager::isRunning() const
{
    return d->timer.isActive();
}

QAbstractSocket *NetworkManager::connection(const QString &hostname, NetworkManager::SocketType socketType) const
{
    return d->socketHash.value(hostname);
}

QAbstractSocket *NetworkManager::createConnection(NetworkManager::SocketType socketType)
{
    QAbstractSocket* socket = d->createSocket(socketType);
    if ( !socket ) {
        qDebug() << "Unknown socket type requested";
        return NULL;
    }

    //d->socketHash.insert(hostname, socket);
    //d->objectHash.insert(hostname, socket);

    return socket;
}

QAbstractSocket *NetworkManager::establishConnection(const QString &hostname, NetworkManager::SocketType socketType)
{
    QAbstractSocket* socket = d->createSocket(socketType);
    if ( !socket ) {
        qDebug() << "Unknown socket type requested";
        return NULL;
    }

    // Step one: Send test offer to peer directly
    // Step two: Send test offer to peer via alive-server
    // Final step: Connect to remote host

    // Step two: Try to connect directly
    RemoteHost remote = NetworkHelper::remoteHost(hostname);
    socket->connectToHost(remote.host, remote.port);
    if (socket->waitForConnected(5000))
        return socket;

    // Step two: Ask alive-server if it can tell the client to hole punch through

    return socket;
}

QTcpServer *NetworkManager::createServerSocket()
{
    // TODO: Connect to traffic counter
    QTcpServer* server = new QTcpServer;
    return server;
}

#include "networkmanager.moc"
<commit_msg>Remotes ..<commit_after>#include "networkmanager.h"
#include "../networkhelper.h"
#include "../log/logger.h"
#include "../settings.h"

#include "tcpsocket.h"
#include "udpsocket.h"

#include <QDataStream>
#include <QJsonDocument>
#include <QPointer>
#include <QTcpServer>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QStringList>
#include <QHash>
#include <QMutex>
#include <QReadWriteLock>
#include <QTimer>
#include <QDebug>

LOGGER(NetworkManager)

class PeerRequest
{
    QVariant toVariant() {
        QVariantMap map;
        map.insert("peer", peer);
        map.insert("port", port);
        map.insert("protocol", protocol);
        return map;
    }

    static PeerRequest fromVariant(const QVariant& variant) {
        QVariantMap map = variant.toMap();

        PeerRequest request;
        request.peer = map.value("peer").toString();
        request.port = map.value("port").toUInt();
        request.protocol = (NetworkManager::SocketType)map.value("protocol").toInt();
        return request;
    }

    QString peer;
    quint16 port;
    NetworkManager::SocketType protocol;
};

class NetworkManager::Private : public QObject
{
    Q_OBJECT

public:
    Private(NetworkManager* q)
    : q(q)
    {
        connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
    }

    NetworkManager* q;

    // Properties
    QMutex mutex;
    QHash<QString, QObject*> objectHash;
    QHash<QString, QAbstractSocket*> socketHash;

    QTimer timer;
    QPointer<QUdpSocket> socket;
    QPointer<Settings> settings;

    quint16 localPort;

    // Functions
    QAbstractSocket* createSocket(NetworkManager::SocketType socketType);

    void updateSocket();
    void updateTimer();
    void processDatagram(const QByteArray& datagram, const QHostAddress& host, quint16 port);

public slots:
    void socketDestroyed(QObject* obj);
    void responseChanged();
    void timeout();
    void onDatagramReady();
};

QAbstractSocket *NetworkManager::Private::createSocket(NetworkManager::SocketType socketType)
{
    QAbstractSocket* socket = NULL;

    switch(socketType) {
    case TcpSocket:
        socket = new ::TcpSocket;
        break;

    case UdpSocket:
        socket = new ::UdpSocket;
        break;

    case UtpSocket:
        //socket = new UtpSocket;
        break;

    default:
        break;
    }

    if (socket) {
        connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(socketDestroyed(QObject*)));
    }

    return socket;
}

void NetworkManager::Private::socketDestroyed(QObject *obj)
{
    QString hostname = objectHash.key(obj);
    if (hostname.isEmpty())
        return;

    objectHash.remove(hostname);
    socketHash.remove(hostname);
}

void NetworkManager::Private::updateSocket()
{
    if (!socket.isNull())
        socket->deleteLater();

    QString keepaliveAddress = settings->config()->keepaliveAddress();
    RemoteHost remote = NetworkHelper::remoteHost(keepaliveAddress);
    if (!remote.isValid())
        return;

    localPort = remote.port;

    socket = qobject_cast<QUdpSocket*>( q->createConnection(NetworkManager::UdpSocket) );
    connect(socket.data(), SIGNAL(readyRead()), this, SLOT(onDatagramReady()));
    if (!socket->bind(remote.port)) {
        LOG_INFO(QString("Unable to bind port %1: %2").arg(remote.port).arg(socket->errorString()));
    }
}

void NetworkManager::Private::updateTimer()
{
    int interval = settings->config()->keepaliveSchedule()->interval();
    if (interval < 1000) {
        LOG_INFO("Keepalive interval < 1 sec will not be accepted.");
        return;
    } else {
        LOG_INFO(QString("Keepalive set to %1 sec.").arg(interval/1000));
    }

    timer.setInterval(interval);
    timer.start();
}

void NetworkManager::Private::processDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)
{
    QString hostAndPort = QString("%1:%2").arg(host.toString()).arg(port);
    if (settings->config()->keepaliveAddress() == hostAndPort) {
        // Master server
        QJsonParseError error;
        QJsonDocument document = QJsonDocument::fromJson(datagram, &error);

        if (error.error == QJsonParseError::NoError) {
            // TODO: Read data
        } else {
            LOG_ERROR(QString("Invalid JSon from master server: %1").arg(error.errorString()));
        }
    } else {
        // TODO: Process incoming data
    }
}

void NetworkManager::Private::responseChanged()
{
    updateSocket();
    updateTimer();

    // Send the first timeout now
    timeout();
}

void NetworkManager::Private::timeout()
{
    RemoteHost remote = NetworkHelper::remoteHost(settings->config()->keepaliveAddress());
    if (!remote.isValid()) {
        LOG_INFO("Invalid keepalive host");
        return;
    }

    QString sessionId = settings->sessionId();
    if (sessionId.isEmpty()) {
        LOG_INFO("Empty session id");
        return;
    }

    QStringList srcIp;
    srcIp.append( NetworkHelper::localIpAddress().toString() );

    QVariantMap map;
    map.insert("type", "keepalive");
    map.insert("session_id", sessionId);
    map.insert("src_ip", srcIp);
    map.insert("src_port", localPort);

    QByteArray data = QJsonDocument::fromVariant(map).toJson();
    socket->writeDatagram(data, QHostAddress(remote.host), remote.port);

    LOG_INFO("Alive packet sent");
}

void NetworkManager::Private::onDatagramReady()
{
    while (socket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(socket->pendingDatagramSize());

        QHostAddress host;
        quint16 port;
        socket->readDatagram(datagram.data(), datagram.size(), &host, &port);

        // Process the datagram
        processDatagram(datagram, host, port);
    }
}

NetworkManager::NetworkManager(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}

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

bool NetworkManager::init(Settings *settings)
{
    connect(settings->config(), SIGNAL(responseChanged()), d, SLOT(responseChanged()));

    d->settings = settings;
    d->responseChanged();
}

void NetworkManager::setRunning(bool running)
{
    if (isRunning() == running)
        return;

    if ( !running )
        d->timer.stop();
    else
        d->updateTimer();
}

bool NetworkManager::isRunning() const
{
    return d->timer.isActive();
}

QAbstractSocket *NetworkManager::connection(const QString &hostname, NetworkManager::SocketType socketType) const
{
    return d->socketHash.value(hostname);
}

QAbstractSocket *NetworkManager::createConnection(NetworkManager::SocketType socketType)
{
    QAbstractSocket* socket = d->createSocket(socketType);
    if ( !socket ) {
        qDebug() << "Unknown socket type requested";
        return NULL;
    }

    //d->socketHash.insert(hostname, socket);
    //d->objectHash.insert(hostname, socket);

    return socket;
}

QAbstractSocket *NetworkManager::establishConnection(const QString &hostname, NetworkManager::SocketType socketType)
{
    QAbstractSocket* socket = d->createSocket(socketType);
    if ( !socket ) {
        qDebug() << "Unknown socket type requested";
        return NULL;
    }

    RemoteHost aliveRemote = NetworkHelper::remoteHost(d->settings->config()->keepaliveAddress());
    RemoteHost remote = NetworkHelper::remoteHost(hostname);

    PeerRequest request;
    request.peer = remote.host;
    request.port = 25000;
    request.protocol = socketType;

    QByteArray data = QJsonDocument::fromVariant(request.toVariant()).toJson();

    // Step one: Send test offer to peer directly
    d->socket->writeDatagram(data, QHostAddress(remote.host), d->localPort);

    // Step two: Send test offer to peer via alive-server
    d->socket->write(data, QHostAddress(aliveRemote.host), aliveRemote.port);

    // Final step: Connect to remote host

    // Step two: Try to connect directly

    socket->connectToHost(remote.host, remote.port);
    if (socket->waitForConnected(5000))
        return socket;

    // Step two: Ask alive-server if it can tell the client to hole punch through

    return socket;
}

QTcpServer *NetworkManager::createServerSocket()
{
    // TODO: Connect to traffic counter
    QTcpServer* server = new QTcpServer;
    return server;
}

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


<commit_before>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

/*
 * This file was originally written in pure C99, but later it had to be migrated to C++.
 * In its current state it's kinda written in C99 with C++ features.
 *
 *                      This is not proper C++.
 */

#include <hal.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <cerrno>

#ifdef STM32F10X_XL
#  error "Add support for XL devices"
#endif

/*
 * The code below assumes that HSI oscillator is up and running,
 * otherwise the Flash controller (FPEC) may misbehave.
 * Any FPEC issues will be detected at run time during write/erase verification.
 */

#define RDP_KEY                 0x00A5
#if !defined(FLASH_KEY1)
# define FLASH_KEY1             0x45670123
# define FLASH_KEY2             0xCDEF89AB
#endif

#if !defined(FLASH_SR_WRPRTERR) // Compatibility
# define FLASH_SR_WRPRTERR      FLASH_SR_WRPERR
#endif

#if defined(STM32F10X_HD) || defined(STM32F10X_HD_VL) || defined(STM32F10X_CL) || defined(STM32F10X_XL)
# define FLASH_SIZE            (*((uint16_t*)0x1FFFF7E0))
# define FLASH_PAGE_SIZE        0x800
#elif defined(STM32F042x6) || defined(STM32F072xB)
# define FLASH_SIZE            (*((uint16_t*)0x1FFFF7CC))
# define FLASH_PAGE_SIZE        0x400
#elif defined(STM32F373xC)
# define FLASH_SIZE            (*((uint16_t*)0x1FFFF7CC))
# define FLASH_PAGE_SIZE        0x800
#else
# error Unknown device.
#endif

#define FLASH_END               ((FLASH_SIZE * 1024) + FLASH_BASE)
#define FLASH_PAGE_ADR          (FLASH_END - FLASH_PAGE_SIZE)
#define DATA_SIZE_MAX           FLASH_PAGE_SIZE

static void waitReady(void)
{
    do
    {
        assert(!(FLASH->SR & FLASH_SR_PGERR));
        assert(!(FLASH->SR & FLASH_SR_WRPRTERR));
    }
    while (FLASH->SR & FLASH_SR_BSY);
    FLASH->SR |= FLASH_SR_EOP;
}

static void prologue(void)
{
    chSysLock();
    waitReady();
    if (FLASH->CR & FLASH_CR_LOCK)
    {
        FLASH->KEYR = FLASH_KEY1;
        FLASH->KEYR = FLASH_KEY2;
    }
    FLASH->SR |= FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // Reset flags
    FLASH->CR = 0;
}

static void epilogue(void)
{
    FLASH->CR = FLASH_CR_LOCK;  // Reset the FPEC configuration and lock
    chSysUnlock();
}

int configStorageRead(unsigned offset, void* data, unsigned len)
{
    if (!data || (offset + len) > DATA_SIZE_MAX)
    {
        assert(0);
        return -EINVAL;
    }

    /*
     * Read directly, FPEC is not involved
     */
    std::memcpy(data, (void*)(FLASH_PAGE_ADR + offset), len);
    return 0;
}

int configStorageWrite(unsigned offset, const void* data, unsigned len)
{
    if (!data || (offset + len) > DATA_SIZE_MAX)
    {
        assert(0);
        return -EINVAL;
    }

    /*
     * Data alignment
     */
    if (((size_t)data) % 2)
    {
        assert(0);
        return -EIO;
    }
    unsigned num_data_halfwords = len / 2;
    if (num_data_halfwords * 2 < len)
    {
        num_data_halfwords += 1;
    }

    /*
     * Write
     */
    prologue();

    FLASH->CR = FLASH_CR_PG;

    volatile uint16_t* flashptr16 = (uint16_t*)(FLASH_PAGE_ADR + offset);
    const uint16_t* ramptr16 = (const uint16_t*)data;
    for (unsigned i = 0; i < num_data_halfwords; i++)
    {
        *flashptr16++ = *ramptr16++;
        waitReady();
    }

    waitReady();
    FLASH->CR = 0;

    epilogue();

    /*
     * Verify
     */
    const int cmpres = memcmp(data, (void*)(FLASH_PAGE_ADR + offset), len);
    return cmpres ? -EIO : 0;
}

int configStorageErase(void)
{
    /*
     * Erase
     */
    prologue();

    FLASH->CR = FLASH_CR_PER;
    FLASH->AR = FLASH_PAGE_ADR;
    FLASH->CR |= FLASH_CR_STRT;

    waitReady();
    FLASH->CR = 0;

    epilogue();

    /*
     * Verify
     */
    for (int i = 0; i < DATA_SIZE_MAX; i++)
    {
        uint8_t* ptr = (uint8_t*)(FLASH_PAGE_ADR + i);
        if (*ptr != 0xFF)
        {
            return -EIO;
        }
    }
    return 0;
}
<commit_msg>F105 compat<commit_after>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

/*
 * This file was originally written in pure C99, but later it had to be migrated to C++.
 * In its current state it's kinda written in C99 with C++ features.
 *
 *                      This is not proper C++.
 */

#include <hal.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <cerrno>

#ifdef STM32F10X_XL
#  error "Add support for XL devices"
#endif

/*
 * The code below assumes that HSI oscillator is up and running,
 * otherwise the Flash controller (FPEC) may misbehave.
 * Any FPEC issues will be detected at run time during write/erase verification.
 */

#if !defined(RDP_KEY)
# define RDP_KEY                0x00A5
#endif

#if !defined(FLASH_KEY1)
# define FLASH_KEY1             0x45670123
# define FLASH_KEY2             0xCDEF89AB
#endif

#if !defined(FLASH_SR_WRPRTERR) // Compatibility
# define FLASH_SR_WRPRTERR      FLASH_SR_WRPERR
#endif

#if defined(STM32F10X_HD) || defined(STM32F10X_HD_VL) || defined(STM32F10X_CL) || defined(STM32F10X_XL)
# define FLASH_SIZE            (*((uint16_t*)0x1FFFF7E0))
# define FLASH_PAGE_SIZE        0x800
#elif defined(STM32F042x6) || defined(STM32F072xB)
# define FLASH_SIZE            (*((uint16_t*)0x1FFFF7CC))
# define FLASH_PAGE_SIZE        0x400
#elif defined(STM32F373xC)
# define FLASH_SIZE            (*((uint16_t*)0x1FFFF7CC))
# define FLASH_PAGE_SIZE        0x800
#else
# error Unknown device.
#endif

#define FLASH_END               ((FLASH_SIZE * 1024) + FLASH_BASE)
#define FLASH_PAGE_ADR          (FLASH_END - FLASH_PAGE_SIZE)
#define DATA_SIZE_MAX           FLASH_PAGE_SIZE

static void waitReady(void)
{
    do
    {
        assert(!(FLASH->SR & FLASH_SR_PGERR));
        assert(!(FLASH->SR & FLASH_SR_WRPRTERR));
    }
    while (FLASH->SR & FLASH_SR_BSY);
    FLASH->SR |= FLASH_SR_EOP;
}

static void prologue(void)
{
    chSysLock();
    waitReady();
    if (FLASH->CR & FLASH_CR_LOCK)
    {
        FLASH->KEYR = FLASH_KEY1;
        FLASH->KEYR = FLASH_KEY2;
    }
    FLASH->SR |= FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // Reset flags
    FLASH->CR = 0;
}

static void epilogue(void)
{
    FLASH->CR = FLASH_CR_LOCK;  // Reset the FPEC configuration and lock
    chSysUnlock();
}

int configStorageRead(unsigned offset, void* data, unsigned len)
{
    if (!data || (offset + len) > DATA_SIZE_MAX)
    {
        assert(0);
        return -EINVAL;
    }

    /*
     * Read directly, FPEC is not involved
     */
    std::memcpy(data, (void*)(FLASH_PAGE_ADR + offset), len);
    return 0;
}

int configStorageWrite(unsigned offset, const void* data, unsigned len)
{
    if (!data || (offset + len) > DATA_SIZE_MAX)
    {
        assert(0);
        return -EINVAL;
    }

    /*
     * Data alignment
     */
    if (((size_t)data) % 2)
    {
        assert(0);
        return -EIO;
    }
    unsigned num_data_halfwords = len / 2;
    if (num_data_halfwords * 2 < len)
    {
        num_data_halfwords += 1;
    }

    /*
     * Write
     */
    prologue();

    FLASH->CR = FLASH_CR_PG;

    volatile uint16_t* flashptr16 = (uint16_t*)(FLASH_PAGE_ADR + offset);
    const uint16_t* ramptr16 = (const uint16_t*)data;
    for (unsigned i = 0; i < num_data_halfwords; i++)
    {
        *flashptr16++ = *ramptr16++;
        waitReady();
    }

    waitReady();
    FLASH->CR = 0;

    epilogue();

    /*
     * Verify
     */
    const int cmpres = memcmp(data, (void*)(FLASH_PAGE_ADR + offset), len);
    return cmpres ? -EIO : 0;
}

int configStorageErase(void)
{
    /*
     * Erase
     */
    prologue();

    FLASH->CR = FLASH_CR_PER;
    FLASH->AR = FLASH_PAGE_ADR;
    FLASH->CR |= FLASH_CR_STRT;

    waitReady();
    FLASH->CR = 0;

    epilogue();

    /*
     * Verify
     */
    for (int i = 0; i < DATA_SIZE_MAX; i++)
    {
        uint8_t* ptr = (uint8_t*)(FLASH_PAGE_ADR + i);
        if (*ptr != 0xFF)
        {
            return -EIO;
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017-2018 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/base/processors/randomspheregenerator.h>
#include <inviwo/core/util/indexmapper.h>

#include <inviwo/core/interaction/events/pickingevent.h>
#include <inviwo/core/interaction/events/mouseevent.h>
#include <inviwo/core/interaction/events/touchevent.h>
#include <inviwo/core/interaction/events/wheelevent.h>
#include <inviwo/core/datastructures/geometry/mesh.h>
#include <inviwo/core/datastructures/buffer/bufferramprecision.h>
#include <inviwo/core/datastructures/buffer/buffer.h>

#include <numeric>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo RandomSphereGenerator::processorInfo_{
    "org.inviwo.RandomSphereGenerator",  // Class identifier
    "Random Sphere Generator",           // Display name
    "Mesh Creation",                     // Category
    CodeState::Stable,                   // Code state
    Tags::CPU,                           // Tags
};
const ProcessorInfo RandomSphereGenerator::getProcessorInfo() const { return processorInfo_; }

RandomSphereGenerator::RandomSphereGenerator()
    : Processor()
    , meshOut_("mesh")
    , seed_("seed", "Seed", 0, 0, std::mt19937::max())
    , reseed_("reseed_", "Seed")
    , scale_("scale", "Scale", 12.0f, 0.001f, 100.0f, 0.1f)
    , size_("size", "Size", 1.0f, 0.001f, 10.0f, 0.1f)
    , gridDim_("gridDim", "Grid Dimension", ivec3(12, 12, 12), ivec3(1), ivec3(128))
    , jigglePos_("jigglePos", "Jiggle Positions", true)
    , enablePicking_("enablePicking", "Enable Picking", false)
    , camera_("camera", "Camera")
    , spherePicking_(
          this, gridDim_.get().x * gridDim_.get().y * gridDim_.get().z, [&](PickingEvent* p) {
              handlePicking(p, [&](vec3 delta) {
                  if (positionBuffer_) {
                      auto& pos = positionBuffer_->getDataContainer();
                      pos[p->getPickedId()] += delta;
                      positionBuffer_->getOwner()->invalidateAllOther(positionBuffer_.get());
                  }
              });
          }) {
    addPort(meshOut_);

    addProperty(scale_);
    addProperty(size_);
    addProperty(gridDim_);
    addProperty(jigglePos_);

    addProperty(seed_);
    addProperty(reseed_);

    addProperty(enablePicking_);
    addProperty(camera_);
    camera_.setInvalidationLevel(InvalidationLevel::Valid);
    camera_.setCollapsed(true);

    reseed_.onChange([&]() {
        seed_.set(static_cast<glm::i64>(rand(0.0f, static_cast<float>(seed_.getMaxValue()))));
        rand_.seed(static_cast<std::mt19937::result_type>(seed_.get()));
    });
}

void RandomSphereGenerator::process() {
    rand_.seed(static_cast<std::mt19937::result_type>(seed_.get()));

    const vec3 bboxMin(-scale_.get());
    const vec3 extent(scale_.get() * 2.0f);
    const vec3 delta(extent / vec3(gridDim_.get()));

    auto randPos = [&]() { return randVec3(-0.5f, 0.5f); };
    auto randColor = [&]() { return vec4(randVec3(0.5, 1.0), 1); };
    auto randRadius = [&]() { return size_.get() * rand(0.1f, 1.0f); };

    const bool dirty = seed_.isModified() || size_.isModified() || scale_.isModified() ||
                       enablePicking_.isModified();

    if (gridDim_.isModified() || dirty || !positionBuffer_) {
        const auto dim = gridDim_.get();
        const int numSpheres = dim.x * dim.y * dim.z;
        spherePicking_.resize(numSpheres);

        auto mesh = std::make_shared<Mesh>(DrawType::Points, ConnectivityType::None);

        auto vertexRAM = std::make_shared<BufferRAMPrecision<vec3>>(numSpheres);
        auto colorRAM = std::make_shared<BufferRAMPrecision<vec4>>(numSpheres);
        auto radiiRAM = std::make_shared<BufferRAMPrecision<float>>(numSpheres);

        // keep a reference to vertex position buffer for picking
        positionBuffer_ = vertexRAM;

        mesh->addBuffer(Mesh::BufferInfo(BufferType::PositionAttrib),
                        std::make_shared<Buffer<vec3>>(vertexRAM));
        mesh->addBuffer(Mesh::BufferInfo(BufferType::ColorAttrib),
                        std::make_shared<Buffer<vec4>>(colorRAM));
        mesh->addBuffer(Mesh::BufferInfo(BufferType::NumberOfBufferTypes, 5),
                        std::make_shared<Buffer<float>>(radiiRAM));
        if (enablePicking_.get()) {
            auto pickingRAM = std::make_shared<BufferRAMPrecision<uint32_t>>(numSpheres);
            auto& data = pickingRAM->getDataContainer();
            // fill in picking IDs
            std::iota(data.begin(), data.end(), static_cast<uint32_t>(spherePicking_.getPickingId(0)));

            mesh->addBuffer(Mesh::BufferInfo(BufferType::NumberOfBufferTypes, 4),
                            std::make_shared<Buffer<uint32_t>>(pickingRAM));
        }

        auto& vertices = vertexRAM->getDataContainer();
        auto& colors = colorRAM->getDataContainer();
        auto& radii = radiiRAM->getDataContainer();

        util::IndexMapper<3, int> indexmapper(dim);
        if (jigglePos_.get()) {
            for (int i = 0; i < numSpheres; i++) {
                vertices[i] = (vec3(indexmapper(i)) + randPos()) * delta + bboxMin;
                colors[i] = randColor();
                radii[i] = randRadius();
            }
        } else {
            for (int i = 0; i < numSpheres; i++) {
                vertices[i] = vec3(indexmapper(i)) * delta + bboxMin;
                colors[i] = randColor();
                radii[i] = randRadius();
            }
        }
        meshOut_.setData(mesh);
    }
}

float RandomSphereGenerator::rand(const float min, const float max) const {
    return min + dis_(rand_) * (max - min);
}

vec3 RandomSphereGenerator::randVec3(const float min, const float max) const {
    float x = rand(min, max);
    float y = rand(min, max);
    float z = rand(min, max);
    return vec3(x, y, z);
}

vec3 RandomSphereGenerator::randVec3(const vec3& min, const vec3& max) const {
    float x = rand(min.x, max.x);
    float y = rand(min.y, max.y);
    float z = rand(min.z, max.z);
    return vec3(x, y, z);
}

void RandomSphereGenerator::handlePicking(PickingEvent* p, std::function<void(vec3)> callback) {
    if (enablePicking_) {
        if (p->getState() == PickingState::Updated &&
            p->getEvent()->hash() == MouseEvent::chash()) {
            auto me = p->getEventAs<MouseEvent>();
            if ((me->buttonState() & MouseButton::Left) && me->state() == MouseState::Move) {
                auto delta = getDelta(camera_, p);
                callback(delta);
                invalidate(InvalidationLevel::InvalidOutput);
                p->markAsUsed();
            }
        } else if (p->getState() == PickingState::Updated &&
                   p->getEvent()->hash() == TouchEvent::chash()) {

            auto te = p->getEventAs<TouchEvent>();
            if (!te->touchPoints().empty() && te->touchPoints()[0].state() == TouchState::Updated) {
                auto delta = getDelta(camera_, p);
                callback(delta);
                invalidate(InvalidationLevel::InvalidOutput);
                p->markAsUsed();
            }
        }
    }
}

vec3 RandomSphereGenerator::getDelta(const Camera& camera, PickingEvent* p) {
    auto currNDC = p->getNDC();
    auto prevNDC = p->getPreviousNDC();

    // Use depth of initial press as reference to move in the image plane.
    auto refDepth = p->getPressedDepth();
    currNDC.z = refDepth;
    prevNDC.z = refDepth;

    auto corrWorld = camera.getWorldPosFromNormalizedDeviceCoords(static_cast<vec3>(currNDC));
    auto prevWorld = camera.getWorldPosFromNormalizedDeviceCoords(static_cast<vec3>(prevNDC));
    return (corrWorld - prevWorld);
}

}  // namespace inviwo
<commit_msg>Base: minor fix * changed property semantics in RandomSphereGenerator<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017-2018 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/base/processors/randomspheregenerator.h>
#include <inviwo/core/util/indexmapper.h>

#include <inviwo/core/interaction/events/pickingevent.h>
#include <inviwo/core/interaction/events/mouseevent.h>
#include <inviwo/core/interaction/events/touchevent.h>
#include <inviwo/core/interaction/events/wheelevent.h>
#include <inviwo/core/datastructures/geometry/mesh.h>
#include <inviwo/core/datastructures/buffer/bufferramprecision.h>
#include <inviwo/core/datastructures/buffer/buffer.h>

#include <numeric>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo RandomSphereGenerator::processorInfo_{
    "org.inviwo.RandomSphereGenerator",  // Class identifier
    "Random Sphere Generator",           // Display name
    "Mesh Creation",                     // Category
    CodeState::Stable,                   // Code state
    Tags::CPU,                           // Tags
};
const ProcessorInfo RandomSphereGenerator::getProcessorInfo() const { return processorInfo_; }

RandomSphereGenerator::RandomSphereGenerator()
    : Processor()
    , meshOut_("mesh")
    , seed_("seed", "Seed", 0, 0, std::mt19937::max())
    , reseed_("reseed_", "Seed")
    , scale_("scale", "Scale", 12.0f, 0.001f, 100.0f, 0.1f)
    , size_("size", "Size", 1.0f, 0.001f, 10.0f, 0.1f)
    , gridDim_("gridDim", "Grid Dimension", ivec3(12, 12, 12), ivec3(1), ivec3(128))
    , jigglePos_("jigglePos", "Jiggle Positions", true)
    , enablePicking_("enablePicking", "Enable Picking", false)
    , camera_("camera", "Camera")
    , spherePicking_(
          this, gridDim_.get().x * gridDim_.get().y * gridDim_.get().z, [&](PickingEvent* p) {
              handlePicking(p, [&](vec3 delta) {
                  if (positionBuffer_) {
                      auto& pos = positionBuffer_->getDataContainer();
                      pos[p->getPickedId()] += delta;
                      positionBuffer_->getOwner()->invalidateAllOther(positionBuffer_.get());
                  }
              });
          }) {
    addPort(meshOut_);

    addProperty(scale_);
    addProperty(size_);
    addProperty(gridDim_);
    addProperty(jigglePos_);

    addProperty(seed_);
    addProperty(reseed_);

    addProperty(enablePicking_);
    addProperty(camera_);
    camera_.setInvalidationLevel(InvalidationLevel::Valid);
    camera_.setCollapsed(true);

    seed_.setSemantics(PropertySemantics::Text);

    reseed_.onChange([&]() {
        seed_.set(static_cast<glm::i64>(rand(0.0f, static_cast<float>(seed_.getMaxValue()))));
        rand_.seed(static_cast<std::mt19937::result_type>(seed_.get()));
    });
}

void RandomSphereGenerator::process() {
    rand_.seed(static_cast<std::mt19937::result_type>(seed_.get()));

    const vec3 bboxMin(-scale_.get());
    const vec3 extent(scale_.get() * 2.0f);
    const vec3 delta(extent / vec3(gridDim_.get()));

    auto randPos = [&]() { return randVec3(-0.5f, 0.5f); };
    auto randColor = [&]() { return vec4(randVec3(0.5, 1.0), 1); };
    auto randRadius = [&]() { return size_.get() * rand(0.1f, 1.0f); };

    const bool dirty = seed_.isModified() || size_.isModified() || scale_.isModified() ||
                       enablePicking_.isModified();

    if (gridDim_.isModified() || dirty || !positionBuffer_) {
        const auto dim = gridDim_.get();
        const int numSpheres = dim.x * dim.y * dim.z;
        spherePicking_.resize(numSpheres);

        auto mesh = std::make_shared<Mesh>(DrawType::Points, ConnectivityType::None);

        auto vertexRAM = std::make_shared<BufferRAMPrecision<vec3>>(numSpheres);
        auto colorRAM = std::make_shared<BufferRAMPrecision<vec4>>(numSpheres);
        auto radiiRAM = std::make_shared<BufferRAMPrecision<float>>(numSpheres);

        // keep a reference to vertex position buffer for picking
        positionBuffer_ = vertexRAM;

        mesh->addBuffer(Mesh::BufferInfo(BufferType::PositionAttrib),
                        std::make_shared<Buffer<vec3>>(vertexRAM));
        mesh->addBuffer(Mesh::BufferInfo(BufferType::ColorAttrib),
                        std::make_shared<Buffer<vec4>>(colorRAM));
        mesh->addBuffer(Mesh::BufferInfo(BufferType::NumberOfBufferTypes, 5),
                        std::make_shared<Buffer<float>>(radiiRAM));
        if (enablePicking_.get()) {
            auto pickingRAM = std::make_shared<BufferRAMPrecision<uint32_t>>(numSpheres);
            auto& data = pickingRAM->getDataContainer();
            // fill in picking IDs
            std::iota(data.begin(), data.end(), static_cast<uint32_t>(spherePicking_.getPickingId(0)));

            mesh->addBuffer(Mesh::BufferInfo(BufferType::NumberOfBufferTypes, 4),
                            std::make_shared<Buffer<uint32_t>>(pickingRAM));
        }

        auto& vertices = vertexRAM->getDataContainer();
        auto& colors = colorRAM->getDataContainer();
        auto& radii = radiiRAM->getDataContainer();

        util::IndexMapper<3, int> indexmapper(dim);
        if (jigglePos_.get()) {
            for (int i = 0; i < numSpheres; i++) {
                vertices[i] = (vec3(indexmapper(i)) + randPos()) * delta + bboxMin;
                colors[i] = randColor();
                radii[i] = randRadius();
            }
        } else {
            for (int i = 0; i < numSpheres; i++) {
                vertices[i] = vec3(indexmapper(i)) * delta + bboxMin;
                colors[i] = randColor();
                radii[i] = randRadius();
            }
        }
        meshOut_.setData(mesh);
    }
}

float RandomSphereGenerator::rand(const float min, const float max) const {
    return min + dis_(rand_) * (max - min);
}

vec3 RandomSphereGenerator::randVec3(const float min, const float max) const {
    float x = rand(min, max);
    float y = rand(min, max);
    float z = rand(min, max);
    return vec3(x, y, z);
}

vec3 RandomSphereGenerator::randVec3(const vec3& min, const vec3& max) const {
    float x = rand(min.x, max.x);
    float y = rand(min.y, max.y);
    float z = rand(min.z, max.z);
    return vec3(x, y, z);
}

void RandomSphereGenerator::handlePicking(PickingEvent* p, std::function<void(vec3)> callback) {
    if (enablePicking_) {
        if (p->getState() == PickingState::Updated &&
            p->getEvent()->hash() == MouseEvent::chash()) {
            auto me = p->getEventAs<MouseEvent>();
            if ((me->buttonState() & MouseButton::Left) && me->state() == MouseState::Move) {
                auto delta = getDelta(camera_, p);
                callback(delta);
                invalidate(InvalidationLevel::InvalidOutput);
                p->markAsUsed();
            }
        } else if (p->getState() == PickingState::Updated &&
                   p->getEvent()->hash() == TouchEvent::chash()) {

            auto te = p->getEventAs<TouchEvent>();
            if (!te->touchPoints().empty() && te->touchPoints()[0].state() == TouchState::Updated) {
                auto delta = getDelta(camera_, p);
                callback(delta);
                invalidate(InvalidationLevel::InvalidOutput);
                p->markAsUsed();
            }
        }
    }
}

vec3 RandomSphereGenerator::getDelta(const Camera& camera, PickingEvent* p) {
    auto currNDC = p->getNDC();
    auto prevNDC = p->getPreviousNDC();

    // Use depth of initial press as reference to move in the image plane.
    auto refDepth = p->getPressedDepth();
    currNDC.z = refDepth;
    prevNDC.z = refDepth;

    auto corrWorld = camera.getWorldPosFromNormalizedDeviceCoords(static_cast<vec3>(currNDC));
    auto prevWorld = camera.getWorldPosFromNormalizedDeviceCoords(static_cast<vec3>(prevNDC));
    return (corrWorld - prevWorld);
}

}  // namespace inviwo
<|endoftext|>


<commit_before>#include "deviceprober.h"
#include "ffbdevice.h"
#include <QtCore/QDebug>
#include <QtWidgets/QMessageBox>
#include <linux/input.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

const QString DeviceProber::DEVICE_NODES_PATH("/dev/input");
const QString DeviceProber::res_ffbdeviceErrCap("FFB Device error");

DeviceProber::DeviceProber(QObject* parent) :
  QObject(parent)
{
}

DeviceProber::DeviceList DeviceProber::listDevices()
{
  DeviceProber::DeviceList list;
  QDir devDir(DEVICE_NODES_PATH);
  //QStringList devices = DeviceProber::s_deviceNodesPath.entryList(QDir::NoDotAndDotDot);
  QStringList devices = devDir.entryList(QDir::System);

  for (const QString& d : devices) {
    int fd, ret;
    char deviceName[64];
    DeviceInfo dinfo;
    QString devicePath = devDir.absoluteFilePath(d);

    fd = open(devicePath.toLocal8Bit(), O_RDWR);
    if (fd == -1) {
      qDebug() << "Device" << d << "unaccessible" << strerror(errno);
      continue;
    }

    dinfo.path = devicePath;
    ret = ioctl(fd, EVIOCGNAME(64), deviceName);
    if (ret < 0)
      qDebug() << "Cannot get name of device" << d << strerror(errno);
    else
      dinfo.name = deviceName;

    list.append(dinfo);
  }

  return list;
}

std::shared_ptr<FFBDevice> DeviceProber::openDevice(const QString& path)
{
  /* Check if the device is already opened */
  for (std::shared_ptr<FFBDevice> dev : m_openedDevices) {
    if (QString::compare(path, dev->path()) == 0) {
      qDebug() << "Device" << path << "already opened";
      return dev;
    }
  }

  int fd = open(path.toLocal8Bit(), O_RDWR);
  if (!fd) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Cannot open device.");
    return nullptr;
  }

  int maxEffectCount;
  int ret = ioctl(fd, EVIOCGEFFECTS, &maxEffectCount);
  if (ret < 0) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Cannot query maximum effects count.\nDevice probably does not support Force Feedback (errno " + QString::number(ret) + ")");
    close(fd);
    return nullptr;
  }
  if (maxEffectCount < 1) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Maximum effect count for this device is zero.");
    close(fd);
    return nullptr;
  }

  std::shared_ptr<FFBDevice> device(new FFBDevice(fd, path, maxEffectCount));
  if (!device->queryDeviceCapabilities()) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Unable to query device capabilities.");
    return nullptr;
  }

  m_openedDevices.push_back(device);
  return device;
}
<commit_msg>Make sure that the deviceName char array is always zero-terminated.<commit_after>#include "deviceprober.h"
#include "ffbdevice.h"
#include <QtCore/QDebug>
#include <QtWidgets/QMessageBox>
#include <linux/input.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

const QString DeviceProber::DEVICE_NODES_PATH("/dev/input");
const QString DeviceProber::res_ffbdeviceErrCap("FFB Device error");

DeviceProber::DeviceProber(QObject* parent) :
  QObject(parent)
{
}

DeviceProber::DeviceList DeviceProber::listDevices()
{
  DeviceProber::DeviceList list;
  char deviceName[64];
  QDir devDir(DEVICE_NODES_PATH);
  //QStringList devices = DeviceProber::s_deviceNodesPath.entryList(QDir::NoDotAndDotDot);
  QStringList devices = devDir.entryList(QDir::System);

  deviceName[63] = '\0';
  for (const QString& d : devices) {
    int fd, ret;
    DeviceInfo dinfo;
    QString devicePath = devDir.absoluteFilePath(d);

    fd = open(devicePath.toLocal8Bit(), O_RDWR);
    if (fd == -1) {
      qDebug() << "Device" << d << "unaccessible" << strerror(errno);
      continue;
    }

    dinfo.path = devicePath;
    ret = ioctl(fd, EVIOCGNAME(63), deviceName);
    if (ret < 0)
      qDebug() << "Cannot get name of device" << d << strerror(errno);
    else
      dinfo.name = deviceName;

    list.append(dinfo);
  }

  return list;
}

std::shared_ptr<FFBDevice> DeviceProber::openDevice(const QString& path)
{
  /* Check if the device is already opened */
  for (std::shared_ptr<FFBDevice> dev : m_openedDevices) {
    if (QString::compare(path, dev->path()) == 0) {
      qDebug() << "Device" << path << "already opened";
      return dev;
    }
  }

  int fd = open(path.toLocal8Bit(), O_RDWR);
  if (!fd) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Cannot open device.");
    return nullptr;
  }

  int maxEffectCount;
  int ret = ioctl(fd, EVIOCGEFFECTS, &maxEffectCount);
  if (ret < 0) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Cannot query maximum effects count.\nDevice probably does not support Force Feedback (errno " + QString::number(ret) + ")");
    close(fd);
    return nullptr;
  }
  if (maxEffectCount < 1) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Maximum effect count for this device is zero.");
    close(fd);
    return nullptr;
  }

  std::shared_ptr<FFBDevice> device(new FFBDevice(fd, path, maxEffectCount));
  if (!device->queryDeviceCapabilities()) {
    QMessageBox::critical(nullptr, res_ffbdeviceErrCap, "Unable to query device capabilities.");
    return nullptr;
  }

  m_openedDevices.push_back(device);
  return device;
}
<|endoftext|>


<commit_before>#include "Optimizer.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include "preprocessor/llvm_includes_end.h"

#include "Arith256.h"
#include "Type.h"

namespace dev
{
namespace eth
{
namespace jit
{

bool optimize(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	//pm.add(llvm::createFunctionInliningPass(2, 2)); // Problem with APInt value bigger than 64bit
	pm.add(llvm::createCFGSimplificationPass());
	pm.add(llvm::createInstructionCombiningPass());
	pm.add(llvm::createAggressiveDCEPass());
	pm.add(llvm::createLowerSwitchPass());
	return pm.run(_module);
}

namespace
{

class LowerEVMPass : public llvm::BasicBlockPass
{
	static char ID;

	bool m_mulFuncNeeded = false;

public:
	LowerEVMPass():
		llvm::BasicBlockPass(ID)
	{}

	virtual bool runOnBasicBlock(llvm::BasicBlock& _bb) override;

	virtual bool doFinalization(llvm::Module& _module) override;
};

char LowerEVMPass::ID = 0;

bool LowerEVMPass::runOnBasicBlock(llvm::BasicBlock& _bb)
{
	auto modified = false;
	auto module = _bb.getParent()->getParent();
	for (auto&& inst : _bb)
	{
		if (inst.getOpcode() == llvm::Instruction::Mul)
		{
			if (inst.getType() == Type::Word)
			{
				auto call = llvm::CallInst::Create(Arith256::getMulFunc(*module), {inst.getOperand(0), inst.getOperand(1)}, "", &inst);
				inst.replaceAllUsesWith(call);
				modified = true;
			}
		}
		else if (inst.getOpcode() == llvm::Instruction::UDiv)
		{
			if (inst.getType() == Type::Word)
			{
				auto call = llvm::CallInst::Create(Arith256::getUDiv256Func(*module), {inst.getOperand(0), inst.getOperand(1)}, "", &inst);
				inst.replaceAllUsesWith(call);
				modified = true;
			}
		}
	}
	return modified;
}

bool LowerEVMPass::doFinalization(llvm::Module&)
{
	return false;
}

}

bool prepare(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	pm.add(llvm::createDeadCodeEliminationPass());
	pm.add(new LowerEVMPass{});
	pm.add(llvm::createDeadInstEliminationPass()); // Remove leftovers
	return pm.run(_module);
}

}
}
}
<commit_msg>Eliminate dead instructions replaced in AP arithmetic lowering.<commit_after>#include "Optimizer.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include "preprocessor/llvm_includes_end.h"

#include "Arith256.h"
#include "Type.h"

namespace dev
{
namespace eth
{
namespace jit
{

bool optimize(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	//pm.add(llvm::createFunctionInliningPass(2, 2)); // Problem with APInt value bigger than 64bit
	pm.add(llvm::createCFGSimplificationPass());
	pm.add(llvm::createInstructionCombiningPass());
	pm.add(llvm::createAggressiveDCEPass());
	pm.add(llvm::createLowerSwitchPass());
	return pm.run(_module);
}

namespace
{

class LowerEVMPass : public llvm::BasicBlockPass
{
	static char ID;

	bool m_mulFuncNeeded = false;

public:
	LowerEVMPass():
		llvm::BasicBlockPass(ID)
	{}

	virtual bool runOnBasicBlock(llvm::BasicBlock& _bb) override;

	virtual bool doFinalization(llvm::Module& _module) override;
};

char LowerEVMPass::ID = 0;

bool LowerEVMPass::runOnBasicBlock(llvm::BasicBlock& _bb)
{
	auto modified = false;
	auto module = _bb.getParent()->getParent();
	for (auto it = _bb.begin(); it != _bb.end(); )
	{
		auto& inst = *it++;
		llvm::Function* func = nullptr;
		if (inst.getType() == Type::Word)
		{
			switch (inst.getOpcode())
			{
			case llvm::Instruction::Mul:
				func = Arith256::getMulFunc(*module);
				break;

			case llvm::Instruction::UDiv:
				func = Arith256::getUDiv256Func(*module);
				break;
			}
		}

		if (func)
		{
			auto call = llvm::CallInst::Create(func, {inst.getOperand(0), inst.getOperand(1)}, "", &inst);
			inst.replaceAllUsesWith(call);
			inst.eraseFromParent();
			modified = true;
		}
	}
	return modified;
}

bool LowerEVMPass::doFinalization(llvm::Module&)
{
	return false;
}

}

bool prepare(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	pm.add(llvm::createDeadCodeEliminationPass());
	pm.add(new LowerEVMPass{});
	return pm.run(_module);
}

}
}
}
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2018 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 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 GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "host/ui/user_tree_item.h"

#include "network/srp_user.h"

namespace aspia {

UserTreeItem::UserTreeItem(size_t index, const SrpUser& user)
    : index_(index)
{
    if (user.flags & SrpUser::ENABLED)
        setIcon(0, QIcon(QStringLiteral(":/img/user.png")));
    else
        setIcon(0, QIcon(QStringLiteral(":/img/user-disabled.png")));

    setText(0, user.name);
}

} // namespace aspia
<commit_msg>- QStringLiteral -> QLatin1String.<commit_after>//
// Aspia Project
// Copyright (C) 2018 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 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 GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "host/ui/user_tree_item.h"

#include "network/srp_user.h"

namespace aspia {

UserTreeItem::UserTreeItem(size_t index, const SrpUser& user)
    : index_(index)
{
    if (user.flags & SrpUser::ENABLED)
        setIcon(0, QIcon(QLatin1String(":/img/user.png")));
    else
        setIcon(0, QIcon(QLatin1String(":/img/user-disabled.png")));

    setText(0, user.name);
}

} // namespace aspia
<|endoftext|>


<commit_before>/*********************************************************************************************************
* Airflow.cc
* Note: Phoenix Airflow tools
* Date: @2015.05
* Author: Force Charlie
* E-mail:<forcemz@outlook.com>
* Copyright (C) 2015 The ForceStudio All Rights Reserved.
**********************************************************************************************************/
#include "Airflow.h"
#include "resource.h"
#include <Prsht.h>
#include <CommCtrl.h>
#include <iostream>

static const wchar_t * stdioimage()
{
    static WCHAR szTemp[MAX_PATH]={0};
    GetTempPathW(MAX_PATH,szTemp);
    wcscat_s(szTemp,MAX_PATH,L"Airflow.Standrand.IO.API.v1.log");
    return szTemp;
}

class RedirectStdIO{
private:
    bool isOpen;
public:
    RedirectStdIO()
    {
        FILE *stream;
        auto err=_wfreopen_s(&stream,stdioimage(),L"w+t", stdout);
        err=_wfreopen_s(&stream,stdioimage(),L"w",stderr);
        if(err==0)
            isOpen=true;
    }
    ~RedirectStdIO()
    {
        ////
        fflush(stdout);
        fclose(stdout);
        fclose(stderr);
    }
};

#define MAXPAGES 5

INT_PTR WINAPI WindowMessageProcess(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    UNREFERENCED_PARAMETER(wParam);
    AirflowStructure *pdata = (AirflowStructure *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    WCHAR szPackagePath[4096]={0};
    WCHAR szRecover[4096]={0};
    switch(uMsg)
    {
        case WM_INITDIALOG:
        {
            PROPSHEETPAGE *psp = (PROPSHEETPAGE *)lParam;
            pdata = (AirflowStructure *)(psp->lParam);
            SetWindowLongPtr(hWnd, GWLP_USERDATA, (DWORD_PTR)pdata);
            ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
            ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
            ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);
            PropSheet_ShowWizButtons(hWnd,0,
                PSWIZB_BACK | PSWIZB_NEXT | PSWIZB_FINISH|PSWIZB_CANCEL);
            if(!pdata->rawfile.empty())
            {
                SetWindowTextW(GetDlgItem(hWnd,IDC_EDIT_FILEURL),pdata->rawfile.c_str());
            }
            if(!pdata->outdir.empty())
            {
                 SetWindowTextW(GetDlgItem(hWnd,IDC_EDIT_FOLDER),pdata->outdir.c_str());
            }
        }
        break;
        case WM_COMMAND:{
            switch (LOWORD(wParam)){
                case IDC_BUTTON_OPENFILE:
                {
                    std::wstring file;
                    auto ret=AirflowFileOpenWindow(hWnd,file,L"Open Installer and Update Package");
                    if(ret){
                        HWND hOEdit=GetDlgItem(hWnd,IDC_EDIT_FILEURL);
                        SetWindowTextW(hOEdit,file.c_str());
                        ////toCheck file type
                        std::wcout<<file<<std::endl;
                    }
                }
                break;
                case IDC_BUTTON_OPENDIR:
                {
                    std::wstring folder;
                    auto ret=AirflowFolderOpenWindow(hWnd,folder,L"Open Installer and Update Package");
                    if(ret){
                        HWND hOEdit=GetDlgItem(hWnd,IDC_EDIT_FOLDER);
                        SetWindowTextW(hOEdit,folder.c_str());
                        ////toCheck file type
                    }
                }
                break;
                case IDC_BUTTON_ENTER:
                {
                    SendDlgItemMessage(hWnd,IDC_PROCESS_RATE,PBM_SETPOS ,50,0L);
                    GetWindowText(GetDlgItem(hWnd,IDC_EDIT_FILEURL),szPackagePath,4096);
                    GetWindowText(GetDlgItem(hWnd,IDC_EDIT_FOLDER),szRecover,4096);
                    if(CheckPackageAfterLayout(szPackagePath,4096,szRecover,4096)){
                        AirflowTaskData *data=new AirflowTaskData();
                        data->isForce=false;
                        data->sendRate=true;
                        data->uMsgid=WM_ASYNCHRONOUS_NOTIFY_MSG;
                        data->hWnd=hWnd;
                        data->mRate=IDC_PROCESS_RATE;
                        data->rawfile=szPackagePath;
                        data->outdir=szRecover;
                        DWORD tId;
                        HANDLE hThread=CreateThread(NULL, 0, AirflowZendMethod, data, 0, &tId);
                        if(!hThread){
                            MessageBoxW(hWnd,L"CreateThread Failed",L"Error",MB_OK);
                        }else{
                            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_ENTER),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENDIR),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENFILE),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FOLDER),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FILEURL),FALSE);
                        }
                    }else{
                    //MessageBoxW(hWnd,)
                    //ShellExecuteW(hWnd,L"open",stdioimage(),NULL,NULL,SW_SHOW);
                    }
                }
                break;
                case IDC_BUTTON_CANCEL:
                {
                    EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_ENTER),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENDIR),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENFILE),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FOLDER),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FILEURL),TRUE);
                    ///Kill Thread and Delete Resource
                    SendDlgItemMessage(hWnd,IDC_PROCESS_RATE,PBM_SETPOS ,0,0L);
                }
                break;
                default:
                break;
            }
        }
        break;
        case WM_ASYNCHRONOUS_NOTIFY_MSG:
        {
            ///En
            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_ENTER),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENDIR),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENFILE),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FOLDER),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FILEURL),TRUE);
        }
        break;
        case WM_NOTIFY:
        break;
        default:
        break;
    }
    return 0;
}

int AirflowUIChannel(AirflowStructure &cArgs)
{
    if(cArgs.cmdMode==CMD_PRINT_VERSION)
    {
        ///
        MessageBoxW(nullptr,AIRFLOW_VERSION_MARK,L"Airflow version box",MB_OK|MB_ICONINFORMATION);
    }else if(cArgs.cmdMode==CMD_PRINT_USAGE)
    {
        MessageBoxW(nullptr,AIRFLOW_USAGE_STRING_GUI,L"Airflow usage:",MB_OK|MB_ICONINFORMATION);
    }
    RedirectStdIO redirectIo;
    PROPSHEETPAGEW   psp;
    HPROPSHEETPAGE  rhpsp[MAXPAGES];
    ZeroMemory(&psp,sizeof(psp));
    ZeroMemory(&rhpsp, sizeof(HPROPSHEETPAGE)*MAXPAGES);
    psp.dwSize=sizeof(psp);
    psp.dwFlags=PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
    psp.lParam=(LPARAM) &cArgs;;
    psp.hInstance=GetModuleHandle(nullptr);
    psp.pszHeaderTitle=L"Select Your Install or Update Package";
    psp.pszTemplate=MAKEINTRESOURCE(IDD_AIRFLOW_FIRST);
    psp.pfnDlgProc=static_cast<DLGPROC>(WindowMessageProcess);
    rhpsp[0]           = CreatePropertySheetPage(&psp);
    if(rhpsp[0]){
        PROPSHEETHEADER psh;  //defines the property sheet
        ZeroMemory(&psh, sizeof(psh));
        psh.dwSize          = sizeof(psh);
        psh.hInstance       = GetModuleHandle(nullptr);
        psh.hwndParent      = NULL;
        psh.phpage          = rhpsp;
        psh.dwFlags         = PSH_AEROWIZARD ;
        psh.pszCaption      = L"Airflow -Recover Windows Installer and Update File";
        psh.pszIcon         = MAKEINTRESOURCE(IDI_WIZICON);
        psh.nStartPage      = 0;
        psh.nPages          = 1;
        if (PropertySheet(&psh) == -1){
            // an error occurred, call GetLastError() to retrieve it here.
            auto LastError=GetLastError();
            std::wstring failedError=L"GetLastError code: ";
            failedError=failedError+std::to_wstring(LastError);
            MessageBoxW(nullptr,failedError.c_str(),L"CreatePropertySheetPage Failed",MB_OK);
        }
    }else{
        DestroyPropertySheetPage(rhpsp[0]);
    }
    return 0;
}<commit_msg>Airflow UI model support Drag Query File<commit_after>/*********************************************************************************************************
* Airflow.cc
* Note: Phoenix Airflow tools
* Date: @2015.05
* Author: Force Charlie
* E-mail:<forcemz@outlook.com>
* Copyright (C) 2015 The ForceStudio All Rights Reserved.
**********************************************************************************************************/
#include "Airflow.h"
#include "resource.h"
#include <Prsht.h>
#include <CommCtrl.h>
#include <iostream>
#include <Shlwapi.h>

static const wchar_t * stdioimage()
{
    static WCHAR szTemp[MAX_PATH]={0};
    GetTempPathW(MAX_PATH,szTemp);
    wcscat_s(szTemp,MAX_PATH,L"Airflow.Standrand.IO.API.v1.log");
    return szTemp;
}

class RedirectStdIO{
private:
    bool isOpen;
public:
    RedirectStdIO()
    {
        FILE *stream;
        auto err=_wfreopen_s(&stream,stdioimage(),L"w+t", stdout);
        err=_wfreopen_s(&stream,stdioimage(),L"w",stderr);
        if(err==0)
            isOpen=true;
    }
    ~RedirectStdIO()
    {
        ////
        fflush(stdout);
        fclose(stdout);
        fclose(stderr);
    }
};

const LPCWSTR PackageSubffix[] = {L".msu", L".msi", L".cab"};
std::vector<std::wstring> vFileList;
#define MAXPAGES 5

INT_PTR WINAPI WindowMessageProcess(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    UNREFERENCED_PARAMETER(wParam);
    AirflowStructure *pdata = (AirflowStructure *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    WCHAR szPackagePath[4096]={0};
    WCHAR szRecover[4096]={0};
    switch(uMsg)
    {
        case WM_INITDIALOG:
        {
            PROPSHEETPAGE *psp = (PROPSHEETPAGE *)lParam;
            pdata = (AirflowStructure *)(psp->lParam);
            SetWindowLongPtr(hWnd, GWLP_USERDATA, (DWORD_PTR)pdata);
            ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
            ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
            ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);
            PropSheet_ShowWizButtons(hWnd,0,
                PSWIZB_BACK | PSWIZB_NEXT | PSWIZB_FINISH|PSWIZB_CANCEL);
            if(!pdata->rawfile.empty())
            {
                SetWindowTextW(GetDlgItem(hWnd,IDC_EDIT_FILEURL),pdata->rawfile.c_str());
            }
            if(!pdata->outdir.empty())
            {
                 SetWindowTextW(GetDlgItem(hWnd,IDC_EDIT_FOLDER),pdata->outdir.c_str());
            }
            DragAcceptFiles(hWnd, TRUE);
        }
        break;
        case WM_COMMAND:{
            switch (LOWORD(wParam)){
                case IDC_BUTTON_OPENFILE:
                {
                    std::wstring file;
                    auto ret=AirflowFileOpenWindow(hWnd,file,L"Open Installer and Update Package");
                    if(ret){
                        HWND hOEdit=GetDlgItem(hWnd,IDC_EDIT_FILEURL);
                        SetWindowTextW(hOEdit,file.c_str());
                        ////toCheck file type
                        std::wcout<<file<<std::endl;
                    }
                }
                break;
                case IDC_BUTTON_OPENDIR:
                {
                    std::wstring folder;
                    auto ret=AirflowFolderOpenWindow(hWnd,folder,L"Open Installer and Update Package");
                    if(ret){
                        HWND hOEdit=GetDlgItem(hWnd,IDC_EDIT_FOLDER);
                        SetWindowTextW(hOEdit,folder.c_str());
                        ////toCheck file type
                    }
                }
                break;
                case IDC_BUTTON_ENTER:
                {
                    SendDlgItemMessage(hWnd,IDC_PROCESS_RATE,PBM_SETPOS ,50,0L);
                    GetWindowText(GetDlgItem(hWnd,IDC_EDIT_FILEURL),szPackagePath,4096);
                    GetWindowText(GetDlgItem(hWnd,IDC_EDIT_FOLDER),szRecover,4096);
                    if(CheckPackageAfterLayout(szPackagePath,4096,szRecover,4096)){
                        AirflowTaskData *data=new AirflowTaskData();
                        data->isForce=false;
                        data->sendRate=true;
                        data->uMsgid=WM_ASYNCHRONOUS_NOTIFY_MSG;
                        data->hWnd=hWnd;
                        data->mRate=IDC_PROCESS_RATE;
                        data->rawfile=szPackagePath;
                        data->outdir=szRecover;
                        DWORD tId;
                        HANDLE hThread=CreateThread(NULL, 0, AirflowZendMethod, data, 0, &tId);
                        if(!hThread){
                            MessageBoxW(hWnd,L"CreateThread Failed",L"Error",MB_OK);
                        }else{
                            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_ENTER),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENDIR),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENFILE),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FOLDER),FALSE);
                            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FILEURL),FALSE);
                        }
                    }else{
                    //MessageBoxW(hWnd,)
                    //ShellExecuteW(hWnd,L"open",stdioimage(),NULL,NULL,SW_SHOW);
                    }
                }
                break;
                case IDC_BUTTON_CANCEL:
                {
                    EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_ENTER),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENDIR),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENFILE),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FOLDER),TRUE);
                    EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FILEURL),TRUE);
                    ///Kill Thread and Delete Resource
                    SendDlgItemMessage(hWnd,IDC_PROCESS_RATE,PBM_SETPOS ,0,0L);
                }
                break;
                default:
                break;
            }
        }
        break;
        case WM_ASYNCHRONOUS_NOTIFY_MSG:
        {
            ///En
            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_ENTER),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENDIR),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_BUTTON_OPENFILE),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FOLDER),TRUE);
            EnableWindow(GetDlgItem(hWnd,IDC_EDIT_FILEURL),TRUE);
        }
        break;
        case WM_DROPFILES:
        {
            HDROP hDrop = (HDROP)wParam;
            UINT nFileNum = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // 拖拽文件个数
            WCHAR strFileName[MAX_PATH];
            for (UINT i = 0; i < nFileNum; i++)
            {
                DragQueryFileW(hDrop, i, strFileName, MAX_PATH);//获得拖曳的文件名
                if(PathFindSuffixArrayW(strFileName,PackageSubffix,ARRAYSIZE(PackageSubffix)))
                {
                    //MessageBoxW(hWnd,L"Have",strFileName,MB_OK);
                    vFileList.push_back(strFileName);
                }
                std::cout<<vFileList.size()<<std::endl;
                if(!vFileList.empty()){
                    SetWindowTextW(GetDlgItem(hWnd,IDC_EDIT_FILEURL),vFileList[0].c_str());
                }
            }
            DragFinish(hDrop);      //释放hDrop
            InvalidateRect(hWnd, NULL, TRUE);
        }
        break;
        case WM_NOTIFY:
        break;
        default:
        break;
    }
    return 0;
}

int AirflowUIChannel(AirflowStructure &cArgs)
{
    if(cArgs.cmdMode==CMD_PRINT_VERSION)
    {
        ///
        MessageBoxW(nullptr,AIRFLOW_VERSION_MARK,L"Airflow version box",MB_OK|MB_ICONINFORMATION);
    }else if(cArgs.cmdMode==CMD_PRINT_USAGE)
    {
        MessageBoxW(nullptr,AIRFLOW_USAGE_STRING_GUI,L"Airflow usage:",MB_OK|MB_ICONINFORMATION);
    }
    RedirectStdIO redirectIo;
    PROPSHEETPAGEW   psp;
    HPROPSHEETPAGE  rhpsp[MAXPAGES];
    ZeroMemory(&psp,sizeof(psp));
    ZeroMemory(&rhpsp, sizeof(HPROPSHEETPAGE)*MAXPAGES);
    psp.dwSize=sizeof(psp);
    psp.dwFlags=PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
    psp.lParam=(LPARAM) &cArgs;;
    psp.hInstance=GetModuleHandle(nullptr);
    psp.pszHeaderTitle=L"Select Your Install or Update Package";
    psp.pszTemplate=MAKEINTRESOURCE(IDD_AIRFLOW_FIRST);
    psp.pfnDlgProc=static_cast<DLGPROC>(WindowMessageProcess);
    rhpsp[0]           = CreatePropertySheetPage(&psp);
    if(rhpsp[0]){
        PROPSHEETHEADER psh;  //defines the property sheet
        ZeroMemory(&psh, sizeof(psh));
        psh.dwSize          = sizeof(psh);
        psh.hInstance       = GetModuleHandle(nullptr);
        psh.hwndParent      = NULL;
        psh.phpage          = rhpsp;
        psh.dwFlags         = PSH_AEROWIZARD ;
        psh.pszCaption      = L"Airflow -Recover Windows Installer and Update File";
        psh.pszIcon         = MAKEINTRESOURCE(IDI_WIZICON);
        psh.nStartPage      = 0;
        psh.nPages          = 1;
        if (PropertySheet(&psh) == -1){
            // an error occurred, call GetLastError() to retrieve it here.
            auto LastError=GetLastError();
            std::wstring failedError=L"GetLastError code: ";
            failedError=failedError+std::to_wstring(LastError);
            MessageBoxW(nullptr,failedError.c_str(),L"CreatePropertySheetPage Failed",MB_OK);
        }
    }else{
        DestroyPropertySheetPage(rhpsp[0]);
    }
    return 0;
}<|endoftext|>