<commit_before>/* Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - 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.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   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 FOUNDATION 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 "murmur_pch.h"
#include "UnixMurmur.h"
#include "Meta.h"

QMutex *LimitTest::qm;
QWaitCondition *LimitTest::qw;
QWaitCondition *LimitTest::qstartw;

LimitTest::LimitTest() : QThread() {
}

void LimitTest::run() {
	qm->lock();
	qstartw->wakeAll();

	qw->wait(qm);
	qm->unlock();
}

void LimitTest::testLimits(QCoreApplication &a) {
	QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance();
	if (QLatin1String(ed->metaObject()->className()) != QLatin1String("QEventDispatcherGlib"))
		qWarning("Not running with glib. While you may be able to open more descriptors, sockets above %d will not work", FD_SETSIZE);
	qWarning("Running descriptor test.");
	int count;
	QList<QFile *> ql;
	for (count=0;count < 524288; ++count) {
		QFile *qf = new QFile(a.applicationFilePath());
		if (qf->open(QIODevice::ReadOnly))
			ql.prepend(qf);
		else
			break;
		if ((count & 1023) == 0)
			qWarning("%d descriptors...", count);
	}
	foreach(QFile *qf, ql)
		delete qf;
	ql.clear();
	qCritical("Managed to open %d descriptors", count);

	qm = new QMutex();
	qw = new QWaitCondition();
	qstartw = new QWaitCondition();

	int fdcount = count / 8;
	if (sizeof(void *) < 8)
		if (fdcount > 1024)
			fdcount = 1024;

	QList<LimitTest *> qtl;
	for (count=0;count < fdcount; ++count) {
		LimitTest *t = new LimitTest();
		t->tid = count;
		qtl << t;
		qm->lock();
		t->start();
		qstartw->wait(qm);
		qm->unlock();
		if (! t->isRunning())
			break;
		if ((count & 511) == 0)
			qWarning("%d threads...", count);
	}
	qm->lock();
	qw->wakeAll();
	qm->unlock();

	foreach(LimitTest *qt, qtl) {
		if (! qt->wait(1000)) {
			qWarning("Thread %d failed to terminate...", qt->tid);
			qt->terminate();
		}
	}
	qFatal("Managed to spawn %d threads", count);
}

extern QFile *qfLog;

int UnixMurmur::iHupFd[2];
int UnixMurmur::iTermFd[2];

UnixMurmur::UnixMurmur() {
	bRoot = true;

	if (geteuid() != 0 && getuid() != 0) {
		bRoot = false;
	}
	if (::socketpair(AF_UNIX, SOCK_STREAM, 0, iHupFd))
		qFatal("Couldn't create HUP socketpair");

	if (::socketpair(AF_UNIX, SOCK_STREAM, 0, iTermFd))
		qFatal("Couldn't create TERM socketpair");

	qsnHup = new QSocketNotifier(iHupFd[1], QSocketNotifier::Read, this);
	qsnTerm = new QSocketNotifier(iTermFd[1], QSocketNotifier::Read, this);

	connect(qsnHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
	connect(qsnTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));

	struct sigaction hup, term;

	hup.sa_handler = hupSignalHandler;
	sigemptyset(&hup.sa_mask);
	hup.sa_flags = SA_RESTART;

	if (sigaction(SIGHUP, &hup, NULL))
		qFatal("Failed to install SIGHUP handler");

	term.sa_handler = termSignalHandler;
	sigemptyset(&term.sa_mask);
	term.sa_flags = SA_RESTART;

	if (sigaction(SIGTERM, &term, NULL))
		qFatal("Failed to install SIGTERM handler");

	umask(S_IRWXO);
}

UnixMurmur::~UnixMurmur() {
	delete qsnHup;
	delete qsnTerm;

	qsnHup = NULL;
	qsnTerm = NULL;

	close(iHupFd[0]);
	close(iHupFd[1]);
	close(iTermFd[0]);
	close(iTermFd[1]);
}

void UnixMurmur::hupSignalHandler(int) {
	char a = 1;
	::write(iHupFd[0], &a, sizeof(a));
}

void UnixMurmur::termSignalHandler(int) {
	char a = 1;
	::write(iTermFd[0], &a, sizeof(a));
}

// Keep these two synchronized with matching actions in DBus.cpp

void UnixMurmur::handleSigHup() {
	qsnHup->setEnabled(false);
	char tmp;
	::read(iHupFd[1], &tmp, sizeof(tmp));

	if (! qfLog || ! qfLog->isOpen()) {
		if (qfLog) {
			qWarning("Caught SIGHUP, but logfile not in use -- interpreting as hint to quit");
			QCoreApplication::instance()->quit();
		} else {
			qWarning("Caught SIGHUP, but logfile not in use");
		}
	} else {
		qWarning("Caught SIGHUP, will reopen %s", qPrintable(Meta::mp.qsLogfile));
		qfLog->close();
		qfLog->setFileName(Meta::mp.qsLogfile);
		bool result = qfLog->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
		if (! result) {
			delete qfLog;
			qfLog = NULL;
		} else {
			qfLog->setTextModeEnabled(true);
			qWarning("Log rotated successfully");
		}
	}
	qsnHup->setEnabled(true);
}

void UnixMurmur::handleSigTerm() {
	qsnTerm->setEnabled(false);
	char tmp;
	::read(iTermFd[1], &tmp, sizeof(tmp));

	qCritical("Caught SIGTERM, exiting");

	QCoreApplication::instance()->quit();

	qsnTerm->setEnabled(true);
}

void UnixMurmur::setuid() {
	if (Meta::mp.uiUid != 0) {
#ifdef Q_OS_DARWIN
		qCritical("WARNING: You are launching murmurd as root on Mac OS X or Darwin. Murmur does not need "
		          "special privileges to set itself up on these systems, so this behavior is highly discouraged.");

		if (::setgid(Meta::mp.uiGid) != 0)
			qFatal("Failed to switch to gid %d", Meta::mp.uiGid);
		if (::setuid(Meta::mp.uiUid) != 0)
			qFatal("Failed to switch to uid %d", Meta::mp.uiUid);

		uid_t uid = getuid(), euid = geteuid();
		gid_t gid = getgid(), egid = getegid();
		if (uid == Meta::mp.uiUid && euid == Meta::mp.uiUid
		        && gid == Meta::mp.uiGid && egid == Meta::mp.uiGid) {
			qCritical("Successfully switched to uid %d", Meta::mp.uiUid);
		} else
			qFatal("Couldn't switch uid/gid.");
#else
		if (::initgroups(qPrintable(Meta::mp.qsName), Meta::mp.uiGid) != 0)
			qCritical("Can't initialize supplementary groups");
		if (::setgid(Meta::mp.uiGid) != 0)
			qCritical("Failed to switch to gid %d", Meta::mp.uiGid);
		if (::setuid(Meta::mp.uiUid) != 0) {
			qFatal("Failed to become uid %d", Meta::mp.uiUid);
		} else {
			qCritical("Successfully switched to uid %d", Meta::mp.uiUid);
			initialcap();
		}
		if (!Meta::mp.qsHome.isEmpty()) {
			// QDir::homePath is broken. It only looks at $HOME
			// instead of getpwuid() so we have to set our home
			// ourselves
			::setenv("HOME", qPrintable(Meta::mp.qsHome), 1);
		}
#endif
	} else if (bRoot) {
		qCritical("WARNING: You are running murmurd as root, without setting a uname in the ini file. This might be a security risk.");
	}
}

void UnixMurmur::initialcap() {
#ifdef Q_OS_LINUX
	cap_value_t caps[] = {CAP_NET_ADMIN, CAP_SETUID, CAP_SETGID, CAP_CHOWN, CAP_SYS_RESOURCE, CAP_DAC_OVERRIDE };

	if (! bRoot)
		return;

	int ncap = sizeof(caps)/sizeof(cap_value_t);

	if (geteuid() != 0)
		ncap--;

	cap_t c = cap_init();
	cap_clear(c);
	cap_set_flag(c, CAP_EFFECTIVE, ncap, caps, CAP_SET);
	cap_set_flag(c, CAP_INHERITABLE, ncap, caps, CAP_SET);
	cap_set_flag(c, CAP_PERMITTED, ncap, caps, CAP_SET);
	if (cap_set_proc(c) != 0) {
		qCritical("Failed to set initial capabilities");
	} else {
		prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
	}
	cap_free(c);
#endif
}

void UnixMurmur::finalcap() {
#ifdef Q_OS_LINUX
	cap_value_t caps[] = {CAP_NET_ADMIN, CAP_SYS_RESOURCE};
	struct rlimit r;

	if (! bRoot)
		return;

	if (getrlimit(RLIMIT_RTPRIO, &r) != 0) {
		qCritical("Failed to get priority limits.");
	} else {
		qWarning("Resource limits were %ld %ld", r.rlim_cur, r.rlim_max);
		r.rlim_cur = r.rlim_max = 1;
		if (setrlimit(RLIMIT_RTPRIO, &r) != 0) {
			qCritical("Failed to set priority limits.");
		}
	}

	int ncap = sizeof(caps)/sizeof(cap_value_t);

	cap_t c = cap_init();
	cap_clear(c);
	cap_set_flag(c, CAP_EFFECTIVE, ncap, caps, CAP_SET);
	cap_set_flag(c, CAP_PERMITTED, ncap, caps, CAP_SET);
	if (cap_set_proc(c) != 0) {
		qCritical("Failed to set final capabilities");
	} else {
		qWarning("Successfully dropped capabilities");
	}
	cap_free(c);
#endif
}
<commit_msg>Make log rotation more robust<commit_after>/* Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - 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.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   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 FOUNDATION 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 "murmur_pch.h"
#include "UnixMurmur.h"
#include "Meta.h"

QMutex *LimitTest::qm;
QWaitCondition *LimitTest::qw;
QWaitCondition *LimitTest::qstartw;

LimitTest::LimitTest() : QThread() {
}

void LimitTest::run() {
	qm->lock();
	qstartw->wakeAll();

	qw->wait(qm);
	qm->unlock();
}

void LimitTest::testLimits(QCoreApplication &a) {
	QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance();
	if (QLatin1String(ed->metaObject()->className()) != QLatin1String("QEventDispatcherGlib"))
		qWarning("Not running with glib. While you may be able to open more descriptors, sockets above %d will not work", FD_SETSIZE);
	qWarning("Running descriptor test.");
	int count;
	QList<QFile *> ql;
	for (count=0;count < 524288; ++count) {
		QFile *qf = new QFile(a.applicationFilePath());
		if (qf->open(QIODevice::ReadOnly))
			ql.prepend(qf);
		else
			break;
		if ((count & 1023) == 0)
			qWarning("%d descriptors...", count);
	}
	foreach(QFile *qf, ql)
		delete qf;
	ql.clear();
	qCritical("Managed to open %d descriptors", count);

	qm = new QMutex();
	qw = new QWaitCondition();
	qstartw = new QWaitCondition();

	int fdcount = count / 8;
	if (sizeof(void *) < 8)
		if (fdcount > 1024)
			fdcount = 1024;

	QList<LimitTest *> qtl;
	for (count=0;count < fdcount; ++count) {
		LimitTest *t = new LimitTest();
		t->tid = count;
		qtl << t;
		qm->lock();
		t->start();
		qstartw->wait(qm);
		qm->unlock();
		if (! t->isRunning())
			break;
		if ((count & 511) == 0)
			qWarning("%d threads...", count);
	}
	qm->lock();
	qw->wakeAll();
	qm->unlock();

	foreach(LimitTest *qt, qtl) {
		if (! qt->wait(1000)) {
			qWarning("Thread %d failed to terminate...", qt->tid);
			qt->terminate();
		}
	}
	qFatal("Managed to spawn %d threads", count);
}

extern QFile *qfLog;

int UnixMurmur::iHupFd[2];
int UnixMurmur::iTermFd[2];

UnixMurmur::UnixMurmur() {
	bRoot = true;

	if (geteuid() != 0 && getuid() != 0) {
		bRoot = false;
	}
	if (::socketpair(AF_UNIX, SOCK_STREAM, 0, iHupFd))
		qFatal("Couldn't create HUP socketpair");

	if (::socketpair(AF_UNIX, SOCK_STREAM, 0, iTermFd))
		qFatal("Couldn't create TERM socketpair");

	qsnHup = new QSocketNotifier(iHupFd[1], QSocketNotifier::Read, this);
	qsnTerm = new QSocketNotifier(iTermFd[1], QSocketNotifier::Read, this);

	connect(qsnHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
	connect(qsnTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));

	struct sigaction hup, term;

	hup.sa_handler = hupSignalHandler;
	sigemptyset(&hup.sa_mask);
	hup.sa_flags = SA_RESTART;

	if (sigaction(SIGHUP, &hup, NULL))
		qFatal("Failed to install SIGHUP handler");

	term.sa_handler = termSignalHandler;
	sigemptyset(&term.sa_mask);
	term.sa_flags = SA_RESTART;

	if (sigaction(SIGTERM, &term, NULL))
		qFatal("Failed to install SIGTERM handler");

	umask(S_IRWXO);
}

UnixMurmur::~UnixMurmur() {
	delete qsnHup;
	delete qsnTerm;

	qsnHup = NULL;
	qsnTerm = NULL;

	close(iHupFd[0]);
	close(iHupFd[1]);
	close(iTermFd[0]);
	close(iTermFd[1]);
}

void UnixMurmur::hupSignalHandler(int) {
	char a = 1;
	ssize_t len = ::write(iHupFd[0], &a, sizeof(a));
	Q_UNUSED(len);
}

void UnixMurmur::termSignalHandler(int) {
	char a = 1;
	ssize_t len = ::write(iTermFd[0], &a, sizeof(a));
	Q_UNUSED(len);
}

// Keep these two synchronized with matching actions in DBus.cpp

void UnixMurmur::handleSigHup() {
	qsnHup->setEnabled(false);
	char tmp;
	ssize_t len = ::read(iHupFd[1], &tmp, sizeof(tmp));
	Q_UNUSED(len);

	if (! qfLog) {
		qWarning("Caught SIGHUP, but logfile not in use");
	} else if (! qfLog->isOpen()) {
		qWarning("Caught SIGHUP, but logfile not in use -- interpreting as hint to quit");
		QCoreApplication::instance()->quit();
	} else {
		qWarning("Caught SIGHUP, will reopen %s", qPrintable(Meta::mp.qsLogfile));

		QFile *newlog = new QFile(Meta::mp.qsLogfile);
		bool result = newlog->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
		if (! result) {
			delete newlog;
			qCritical("Failed to reopen logfile for writing, keeping old log");
		} else {
			QFile *oldlog = qfLog;

			newlog->setTextModeEnabled(true);
			qfLog = newlog;
			oldlog->close();
			delete oldlog;
			qWarning("Log rotated successfully");
		}
	}
	qsnHup->setEnabled(true);
}

void UnixMurmur::handleSigTerm() {
	qsnTerm->setEnabled(false);
	char tmp;
	ssize_t len = ::read(iTermFd[1], &tmp, sizeof(tmp));
	Q_UNUSED(len);

	qCritical("Caught SIGTERM, exiting");

	QCoreApplication::instance()->quit();

	qsnTerm->setEnabled(true);
}

void UnixMurmur::setuid() {
	if (Meta::mp.uiUid != 0) {
#ifdef Q_OS_DARWIN
		qCritical("WARNING: You are launching murmurd as root on Mac OS X or Darwin. Murmur does not need "
		          "special privileges to set itself up on these systems, so this behavior is highly discouraged.");

		if (::setgid(Meta::mp.uiGid) != 0)
			qFatal("Failed to switch to gid %d", Meta::mp.uiGid);
		if (::setuid(Meta::mp.uiUid) != 0)
			qFatal("Failed to switch to uid %d", Meta::mp.uiUid);

		uid_t uid = getuid(), euid = geteuid();
		gid_t gid = getgid(), egid = getegid();
		if (uid == Meta::mp.uiUid && euid == Meta::mp.uiUid
		        && gid == Meta::mp.uiGid && egid == Meta::mp.uiGid) {
			qCritical("Successfully switched to uid %d", Meta::mp.uiUid);
		} else
			qFatal("Couldn't switch uid/gid.");
#else
		if (::initgroups(qPrintable(Meta::mp.qsName), Meta::mp.uiGid) != 0)
			qCritical("Can't initialize supplementary groups");
		if (::setgid(Meta::mp.uiGid) != 0)
			qCritical("Failed to switch to gid %d", Meta::mp.uiGid);
		if (::setuid(Meta::mp.uiUid) != 0) {
			qFatal("Failed to become uid %d", Meta::mp.uiUid);
		} else {
			qCritical("Successfully switched to uid %d", Meta::mp.uiUid);
			initialcap();
		}
		if (!Meta::mp.qsHome.isEmpty()) {
			// QDir::homePath is broken. It only looks at $HOME
			// instead of getpwuid() so we have to set our home
			// ourselves
			::setenv("HOME", qPrintable(Meta::mp.qsHome), 1);
		}
#endif
	} else if (bRoot) {
		qCritical("WARNING: You are running murmurd as root, without setting a uname in the ini file. This might be a security risk.");
	}
}

void UnixMurmur::initialcap() {
#ifdef Q_OS_LINUX
	cap_value_t caps[] = {CAP_NET_ADMIN, CAP_SETUID, CAP_SETGID, CAP_CHOWN, CAP_SYS_RESOURCE, CAP_DAC_OVERRIDE };

	if (! bRoot)
		return;

	int ncap = sizeof(caps)/sizeof(cap_value_t);

	if (geteuid() != 0)
		ncap--;

	cap_t c = cap_init();
	cap_clear(c);
	cap_set_flag(c, CAP_EFFECTIVE, ncap, caps, CAP_SET);
	cap_set_flag(c, CAP_INHERITABLE, ncap, caps, CAP_SET);
	cap_set_flag(c, CAP_PERMITTED, ncap, caps, CAP_SET);
	if (cap_set_proc(c) != 0) {
		qCritical("Failed to set initial capabilities");
	} else {
		prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
	}
	cap_free(c);
#endif
}

void UnixMurmur::finalcap() {
#ifdef Q_OS_LINUX
	cap_value_t caps[] = {CAP_NET_ADMIN, CAP_SYS_RESOURCE};
	struct rlimit r;

	if (! bRoot)
		return;

	if (getrlimit(RLIMIT_RTPRIO, &r) != 0) {
		qCritical("Failed to get priority limits.");
	} else {
		qWarning("Resource limits were %ld %ld", r.rlim_cur, r.rlim_max);
		r.rlim_cur = r.rlim_max = 1;
		if (setrlimit(RLIMIT_RTPRIO, &r) != 0) {
			qCritical("Failed to set priority limits.");
		}
	}

	int ncap = sizeof(caps)/sizeof(cap_value_t);

	cap_t c = cap_init();
	cap_clear(c);
	cap_set_flag(c, CAP_EFFECTIVE, ncap, caps, CAP_SET);
	cap_set_flag(c, CAP_PERMITTED, ncap, caps, CAP_SET);
	if (cap_set_proc(c) != 0) {
		qCritical("Failed to set final capabilities");
	} else {
		qWarning("Successfully dropped capabilities");
	}
	cap_free(c);
#endif
}
<|endoftext|>


<commit_before>//===- utils/TableGen/X86EVEX2VEXTablesEmitter.cpp - X86 backend-*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// This tablegen backend is responsible for emitting the X86 backend EVEX2VEX
/// compression tables.
///
//===----------------------------------------------------------------------===//

#include "CodeGenTarget.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"

using namespace llvm;

namespace {

class X86EVEX2VEXTablesEmitter {
  RecordKeeper &Records;
  CodeGenTarget Target;

  // Hold all non-masked & non-broadcasted EVEX encoded instructions
  std::vector<const CodeGenInstruction *> EVEXInsts;
  // Hold all VEX encoded instructions. Divided into groups with same opcodes
  // to make the search more efficient
  std::map<uint64_t, std::vector<const CodeGenInstruction *>> VEXInsts;

  typedef std::pair<const CodeGenInstruction *, const CodeGenInstruction *> Entry;

  // Represent both compress tables
  std::vector<Entry> EVEX2VEX128;
  std::vector<Entry> EVEX2VEX256;

public:
  X86EVEX2VEXTablesEmitter(RecordKeeper &R) : Records(R), Target(R) {}

  // run - Output X86 EVEX2VEX tables.
  void run(raw_ostream &OS);

private:
  // Prints the given table as a C++ array of type
  // X86EvexToVexCompressTableEntry
  void printTable(const std::vector<Entry> &Table, raw_ostream &OS);
};

void X86EVEX2VEXTablesEmitter::printTable(const std::vector<Entry> &Table,
                                          raw_ostream &OS) {
  StringRef Size = (Table == EVEX2VEX128) ? "128" : "256";

  OS << "// X86 EVEX encoded instructions that have a VEX " << Size
     << " encoding\n"
     << "// (table format: <EVEX opcode, VEX-" << Size << " opcode>).\n"
     << "static const X86EvexToVexCompressTableEntry X86EvexToVex" << Size
     << "CompressTable[] = {\n"
     << "  // EVEX scalar with corresponding VEX.\n";

  // Print all entries added to the table
  for (auto Pair : Table) {
    OS << "  { X86::" << Pair.first->TheDef->getName()
       << ", X86::" << Pair.second->TheDef->getName() << " },\n";
  }

  OS << "};\n\n";
}

// Return true if the 2 BitsInits are equal
// Calculates the integer value residing BitsInit object
static inline uint64_t getValueFromBitsInit(const BitsInit *B) {
  uint64_t Value = 0;
  for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
    if (BitInit *Bit = dyn_cast<BitInit>(B->getBit(i)))
      Value |= uint64_t(Bit->getValue()) << i;
    else
      PrintFatalError("Invalid VectSize bit");
  }
  return Value;
}

// Function object - Operator() returns true if the given VEX instruction
// matches the EVEX instruction of this object.
class IsMatch {
  const CodeGenInstruction *EVEXInst;

public:
  IsMatch(const CodeGenInstruction *EVEXInst) : EVEXInst(EVEXInst) {}

  bool operator()(const CodeGenInstruction *VEXInst) {
    Record *RecE = EVEXInst->TheDef;
    Record *RecV = VEXInst->TheDef;
    bool EVEX_W = RecE->getValueAsBit("HasVEX_W");
    bool VEX_W  = RecV->getValueAsBit("HasVEX_W");
    bool VEX_WIG  = RecV->getValueAsBit("IgnoresVEX_W");
    bool EVEX_WIG = RecE->getValueAsBit("IgnoresVEX_W");
    bool EVEX_W1_VEX_W0 = RecE->getValueAsBit("EVEX_W1_VEX_W0");

    if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" ||
        // VEX/EVEX fields
        RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") ||
        RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") ||
        RecV->getValueAsBit("hasVEX_4V") != RecE->getValueAsBit("hasVEX_4V") ||
        RecV->getValueAsBit("hasEVEX_L2") != RecE->getValueAsBit("hasEVEX_L2") ||
        RecV->getValueAsBit("hasVEX_L") != RecE->getValueAsBit("hasVEX_L") ||
        // Match is allowed if either is VEX_WIG, or they match, or EVEX
        // is VEX_W1X and VEX is VEX_W0.
        (!(VEX_WIG || (!EVEX_WIG && EVEX_W == VEX_W) ||
           (EVEX_W1_VEX_W0 && EVEX_W && !VEX_W))) ||
        // Instruction's format
        RecV->getValueAsDef("Form") != RecE->getValueAsDef("Form") ||
        RecV->getValueAsBit("isAsmParserOnly") !=
            RecE->getValueAsBit("isAsmParserOnly"))
      return false;

    // This is needed for instructions with intrinsic version (_Int).
    // Where the only difference is the size of the operands.
    // For example: VUCOMISDZrm and Int_VUCOMISDrm
    // Also for instructions that their EVEX version was upgraded to work with
    // k-registers. For example VPCMPEQBrm (xmm output register) and
    // VPCMPEQBZ128rm (k register output register).
    for (unsigned i = 0, e = EVEXInst->Operands.size(); i < e; i++) {
      Record *OpRec1 = EVEXInst->Operands[i].Rec;
      Record *OpRec2 = VEXInst->Operands[i].Rec;

      if (OpRec1 == OpRec2)
        continue;

      if (isRegisterOperand(OpRec1) && isRegisterOperand(OpRec2)) {
        if (getRegOperandSize(OpRec1) != getRegOperandSize(OpRec2))
          return false;
      } else if (isMemoryOperand(OpRec1) && isMemoryOperand(OpRec2)) {
        return false;
      } else if (isImmediateOperand(OpRec1) && isImmediateOperand(OpRec2)) {
        if (OpRec1->getValueAsDef("Type") != OpRec2->getValueAsDef("Type")) {
          return false;
        }
      } else
        return false;
    }

    return true;
  }

private:
  static inline bool isRegisterOperand(const Record *Rec) {
    return Rec->isSubClassOf("RegisterClass") ||
           Rec->isSubClassOf("RegisterOperand");
  }

  static inline bool isMemoryOperand(const Record *Rec) {
    return Rec->isSubClassOf("Operand") &&
           Rec->getValueAsString("OperandType") == "OPERAND_MEMORY";
  }

  static inline bool isImmediateOperand(const Record *Rec) {
    return Rec->isSubClassOf("Operand") &&
           Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE";
  }

  static inline unsigned int getRegOperandSize(const Record *RegRec) {
    if (RegRec->isSubClassOf("RegisterClass"))
      return RegRec->getValueAsInt("Alignment");
    if (RegRec->isSubClassOf("RegisterOperand"))
      return RegRec->getValueAsDef("RegClass")->getValueAsInt("Alignment");

    llvm_unreachable("Register operand's size not known!");
  }
};

void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) {
  emitSourceFileHeader("X86 EVEX2VEX tables", OS);

  ArrayRef<const CodeGenInstruction *> NumberedInstructions =
      Target.getInstructionsByEnumValue();

  for (const CodeGenInstruction *Inst : NumberedInstructions) {
    // Filter non-X86 instructions.
    if (!Inst->TheDef->isSubClassOf("X86Inst"))
      continue;

    // Add VEX encoded instructions to one of VEXInsts vectors according to
    // it's opcode.
    if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncVEX") {
      uint64_t Opcode = getValueFromBitsInit(Inst->TheDef->
                                             getValueAsBitsInit("Opcode"));
      VEXInsts[Opcode].push_back(Inst);
    }
    // Add relevant EVEX encoded instructions to EVEXInsts
    else if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncEVEX" &&
             !Inst->TheDef->getValueAsBit("hasEVEX_K") &&
             !Inst->TheDef->getValueAsBit("hasEVEX_B") &&
             !Inst->TheDef->getValueAsBit("hasEVEX_L2") &&
             !Inst->TheDef->getValueAsBit("notEVEX2VEXConvertible"))
      EVEXInsts.push_back(Inst);
  }

  for (const CodeGenInstruction *EVEXInst : EVEXInsts) {
    uint64_t Opcode = getValueFromBitsInit(EVEXInst->TheDef->
                                           getValueAsBitsInit("Opcode"));
    // For each EVEX instruction look for a VEX match in the appropriate vector
    // (instructions with the same opcode) using function object IsMatch.
    // Allow EVEX2VEXOverride to explicitly specify a match.
    const CodeGenInstruction *VEXInst = nullptr;
    if (!EVEXInst->TheDef->isValueUnset("EVEX2VEXOverride")) {
      StringRef AltInstStr =
        EVEXInst->TheDef->getValueAsString("EVEX2VEXOverride");
      Record *AltInstRec = Records.getDef(AltInstStr);
      assert(AltInstRec && "EVEX2VEXOverride instruction not found!");
      VEXInst = &Target.getInstruction(AltInstRec);
    } else {
      auto Match = llvm::find_if(VEXInsts[Opcode], IsMatch(EVEXInst));
      if (Match != VEXInsts[Opcode].end())
        VEXInst = *Match;
    }

    if (!VEXInst)
      continue;

    // In case a match is found add new entry to the appropriate table
    if (EVEXInst->TheDef->getValueAsBit("hasVEX_L"))
      EVEX2VEX256.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,1}
    else
      EVEX2VEX128.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,0}
  }

  // Print both tables
  printTable(EVEX2VEX128, OS);
  printTable(EVEX2VEX256, OS);
}
}

namespace llvm {
void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS) {
  X86EVEX2VEXTablesEmitter(RK).run(OS);
}
}
<commit_msg>[X86] Remove check on isAsmParserOnly from EVEX2VEX tablegenerator. NFCI<commit_after>//===- utils/TableGen/X86EVEX2VEXTablesEmitter.cpp - X86 backend-*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// This tablegen backend is responsible for emitting the X86 backend EVEX2VEX
/// compression tables.
///
//===----------------------------------------------------------------------===//

#include "CodeGenTarget.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"

using namespace llvm;

namespace {

class X86EVEX2VEXTablesEmitter {
  RecordKeeper &Records;
  CodeGenTarget Target;

  // Hold all non-masked & non-broadcasted EVEX encoded instructions
  std::vector<const CodeGenInstruction *> EVEXInsts;
  // Hold all VEX encoded instructions. Divided into groups with same opcodes
  // to make the search more efficient
  std::map<uint64_t, std::vector<const CodeGenInstruction *>> VEXInsts;

  typedef std::pair<const CodeGenInstruction *, const CodeGenInstruction *> Entry;

  // Represent both compress tables
  std::vector<Entry> EVEX2VEX128;
  std::vector<Entry> EVEX2VEX256;

public:
  X86EVEX2VEXTablesEmitter(RecordKeeper &R) : Records(R), Target(R) {}

  // run - Output X86 EVEX2VEX tables.
  void run(raw_ostream &OS);

private:
  // Prints the given table as a C++ array of type
  // X86EvexToVexCompressTableEntry
  void printTable(const std::vector<Entry> &Table, raw_ostream &OS);
};

void X86EVEX2VEXTablesEmitter::printTable(const std::vector<Entry> &Table,
                                          raw_ostream &OS) {
  StringRef Size = (Table == EVEX2VEX128) ? "128" : "256";

  OS << "// X86 EVEX encoded instructions that have a VEX " << Size
     << " encoding\n"
     << "// (table format: <EVEX opcode, VEX-" << Size << " opcode>).\n"
     << "static const X86EvexToVexCompressTableEntry X86EvexToVex" << Size
     << "CompressTable[] = {\n"
     << "  // EVEX scalar with corresponding VEX.\n";

  // Print all entries added to the table
  for (auto Pair : Table) {
    OS << "  { X86::" << Pair.first->TheDef->getName()
       << ", X86::" << Pair.second->TheDef->getName() << " },\n";
  }

  OS << "};\n\n";
}

// Return true if the 2 BitsInits are equal
// Calculates the integer value residing BitsInit object
static inline uint64_t getValueFromBitsInit(const BitsInit *B) {
  uint64_t Value = 0;
  for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
    if (BitInit *Bit = dyn_cast<BitInit>(B->getBit(i)))
      Value |= uint64_t(Bit->getValue()) << i;
    else
      PrintFatalError("Invalid VectSize bit");
  }
  return Value;
}

// Function object - Operator() returns true if the given VEX instruction
// matches the EVEX instruction of this object.
class IsMatch {
  const CodeGenInstruction *EVEXInst;

public:
  IsMatch(const CodeGenInstruction *EVEXInst) : EVEXInst(EVEXInst) {}

  bool operator()(const CodeGenInstruction *VEXInst) {
    Record *RecE = EVEXInst->TheDef;
    Record *RecV = VEXInst->TheDef;
    bool EVEX_W = RecE->getValueAsBit("HasVEX_W");
    bool VEX_W  = RecV->getValueAsBit("HasVEX_W");
    bool VEX_WIG  = RecV->getValueAsBit("IgnoresVEX_W");
    bool EVEX_WIG = RecE->getValueAsBit("IgnoresVEX_W");
    bool EVEX_W1_VEX_W0 = RecE->getValueAsBit("EVEX_W1_VEX_W0");

    if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" ||
        // VEX/EVEX fields
        RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") ||
        RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") ||
        RecV->getValueAsBit("hasVEX_4V") != RecE->getValueAsBit("hasVEX_4V") ||
        RecV->getValueAsBit("hasEVEX_L2") != RecE->getValueAsBit("hasEVEX_L2") ||
        RecV->getValueAsBit("hasVEX_L") != RecE->getValueAsBit("hasVEX_L") ||
        // Match is allowed if either is VEX_WIG, or they match, or EVEX
        // is VEX_W1X and VEX is VEX_W0.
        (!(VEX_WIG || (!EVEX_WIG && EVEX_W == VEX_W) ||
           (EVEX_W1_VEX_W0 && EVEX_W && !VEX_W))) ||
        // Instruction's format
        RecV->getValueAsDef("Form") != RecE->getValueAsDef("Form"))
      return false;

    // This is needed for instructions with intrinsic version (_Int).
    // Where the only difference is the size of the operands.
    // For example: VUCOMISDZrm and Int_VUCOMISDrm
    // Also for instructions that their EVEX version was upgraded to work with
    // k-registers. For example VPCMPEQBrm (xmm output register) and
    // VPCMPEQBZ128rm (k register output register).
    for (unsigned i = 0, e = EVEXInst->Operands.size(); i < e; i++) {
      Record *OpRec1 = EVEXInst->Operands[i].Rec;
      Record *OpRec2 = VEXInst->Operands[i].Rec;

      if (OpRec1 == OpRec2)
        continue;

      if (isRegisterOperand(OpRec1) && isRegisterOperand(OpRec2)) {
        if (getRegOperandSize(OpRec1) != getRegOperandSize(OpRec2))
          return false;
      } else if (isMemoryOperand(OpRec1) && isMemoryOperand(OpRec2)) {
        return false;
      } else if (isImmediateOperand(OpRec1) && isImmediateOperand(OpRec2)) {
        if (OpRec1->getValueAsDef("Type") != OpRec2->getValueAsDef("Type")) {
          return false;
        }
      } else
        return false;
    }

    return true;
  }

private:
  static inline bool isRegisterOperand(const Record *Rec) {
    return Rec->isSubClassOf("RegisterClass") ||
           Rec->isSubClassOf("RegisterOperand");
  }

  static inline bool isMemoryOperand(const Record *Rec) {
    return Rec->isSubClassOf("Operand") &&
           Rec->getValueAsString("OperandType") == "OPERAND_MEMORY";
  }

  static inline bool isImmediateOperand(const Record *Rec) {
    return Rec->isSubClassOf("Operand") &&
           Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE";
  }

  static inline unsigned int getRegOperandSize(const Record *RegRec) {
    if (RegRec->isSubClassOf("RegisterClass"))
      return RegRec->getValueAsInt("Alignment");
    if (RegRec->isSubClassOf("RegisterOperand"))
      return RegRec->getValueAsDef("RegClass")->getValueAsInt("Alignment");

    llvm_unreachable("Register operand's size not known!");
  }
};

void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) {
  emitSourceFileHeader("X86 EVEX2VEX tables", OS);

  ArrayRef<const CodeGenInstruction *> NumberedInstructions =
      Target.getInstructionsByEnumValue();

  for (const CodeGenInstruction *Inst : NumberedInstructions) {
    // Filter non-X86 instructions.
    if (!Inst->TheDef->isSubClassOf("X86Inst"))
      continue;

    // Add VEX encoded instructions to one of VEXInsts vectors according to
    // it's opcode.
    if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncVEX") {
      uint64_t Opcode = getValueFromBitsInit(Inst->TheDef->
                                             getValueAsBitsInit("Opcode"));
      VEXInsts[Opcode].push_back(Inst);
    }
    // Add relevant EVEX encoded instructions to EVEXInsts
    else if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncEVEX" &&
             !Inst->TheDef->getValueAsBit("hasEVEX_K") &&
             !Inst->TheDef->getValueAsBit("hasEVEX_B") &&
             !Inst->TheDef->getValueAsBit("hasEVEX_L2") &&
             !Inst->TheDef->getValueAsBit("notEVEX2VEXConvertible"))
      EVEXInsts.push_back(Inst);
  }

  for (const CodeGenInstruction *EVEXInst : EVEXInsts) {
    uint64_t Opcode = getValueFromBitsInit(EVEXInst->TheDef->
                                           getValueAsBitsInit("Opcode"));
    // For each EVEX instruction look for a VEX match in the appropriate vector
    // (instructions with the same opcode) using function object IsMatch.
    // Allow EVEX2VEXOverride to explicitly specify a match.
    const CodeGenInstruction *VEXInst = nullptr;
    if (!EVEXInst->TheDef->isValueUnset("EVEX2VEXOverride")) {
      StringRef AltInstStr =
        EVEXInst->TheDef->getValueAsString("EVEX2VEXOverride");
      Record *AltInstRec = Records.getDef(AltInstStr);
      assert(AltInstRec && "EVEX2VEXOverride instruction not found!");
      VEXInst = &Target.getInstruction(AltInstRec);
    } else {
      auto Match = llvm::find_if(VEXInsts[Opcode], IsMatch(EVEXInst));
      if (Match != VEXInsts[Opcode].end())
        VEXInst = *Match;
    }

    if (!VEXInst)
      continue;

    // In case a match is found add new entry to the appropriate table
    if (EVEXInst->TheDef->getValueAsBit("hasVEX_L"))
      EVEX2VEX256.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,1}
    else
      EVEX2VEX128.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,0}
  }

  // Print both tables
  printTable(EVEX2VEX128, OS);
  printTable(EVEX2VEX256, OS);
}
}

namespace llvm {
void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS) {
  X86EVEX2VEXTablesEmitter(RK).run(OS);
}
}
<|endoftext|>


<commit_before>#include "pcloudapp.h"
#include "common.h"
#include <QMenu>
#include <QProcess>
#include <QUrl>
#include <QDir>
#include <QDesktopServices>

void PCloudApp::hideAllWindows(){
    if (reglog)
        reglog->hide();
    if (regwin)
        regwin->hide();
    if (logwin)
        logwin->hide();
    if (settingswin)
        settingswin->hide();
    if (incomingshareswin)
        incomingshareswin->hide();
    if (outgoingshareswin)
        outgoingshareswin->hide();
}

void PCloudApp::setUser(binresult *userinfo){
    emit logInSignal(find_res(userinfo, "auth")->str, find_res(userinfo, "email")->str);
}

void PCloudApp::showWindow(QMainWindow *win)
{
    win->raise();
    win->activateWindow();
    win->showNormal();
    win->setWindowState(Qt::WindowActive);
    this->setActiveWindow(win);
}

void PCloudApp::showRegLog(){
    hideAllWindows();
    if (!reglog)
        reglog=new RegLogWindow(this);
    showWindow(reglog);
}

void PCloudApp::showRegister(){
    hideAllWindows();
    if (!regwin)
        regwin=new RegisterWindow(this);
    showWindow(regwin);
}

void PCloudApp::showLogin(){
    hideAllWindows();
    if (!logwin)
        logwin=new LoginWindow(this);
    showWindow(logwin);
}

void PCloudApp::showSettings(){
    hideAllWindows();
    if (!settingswin)
        settingswin=new SettingsWindow(this);
    showWindow(settingswin);
}

void PCloudApp::openCloudDir(){
    QDesktopServices::openUrl(QUrl::fromLocalFile(settings->get("path")));
}

void PCloudApp::shareFolder(){
    hideAllWindows();
    if (!sharefolderwin)
        sharefolderwin=new ShareFolderWindow(this);
    showWindow(sharefolderwin);
}

void PCloudApp::outgoingShares(){
    hideAllWindows();
    if (!outgoingshareswin)
        outgoingshareswin=new SharesWindow(this, 0);
    showWindow(outgoingshareswin);
}

void PCloudApp::incomingShares()
{
    hideAllWindows();
    if (!incomingshareswin)
        incomingshareswin=new SharesWindow(this, 1);
    showWindow(incomingshareswin);
}

void PCloudApp::logOut(){
    loggedin=false;
    username="";
    tray->setContextMenu(notloggedmenu);
    tray->setToolTip("pCloud");
    tray->setIcon(QIcon(OFFLINE_ICON));
    settings->unset("auth");
    unMount();
}

void PCloudApp::upgradePlan()
{
    QUrl url("https://my.pcloud.com/#page=plans&authtoken="+settings->get("auth"));
    QDesktopServices::openUrl(url);
}

void PCloudApp::doExit(){
    unMount();
    quit();
}

void PCloudApp::trayClicked(QSystemTrayIcon::ActivationReason reason){
    if (reason==QSystemTrayIcon::Trigger){
        if (loggedin)
            openCloudDir();
        else
            showLogin();
    }
}

void PCloudApp::createMenus(){
    notloggedmenu=new QMenu();
    registerAction=new QAction("Register", this);
    connect(registerAction, SIGNAL(triggered()), this, SLOT(showRegister()));
    notloggedmenu->addAction(registerAction);
    loginAction=new QAction("Login", this);
    connect(loginAction, SIGNAL(triggered()), this, SLOT(showLogin()));
    notloggedmenu->addAction(loginAction);
    settingsAction=new QAction("Settings", this);
    connect(settingsAction, SIGNAL(triggered()), this, SLOT(showSettings()));
    notloggedmenu->addAction(settingsAction);
    notloggedmenu->addSeparator();
    exitAction=new QAction("Exit", this);
    connect(exitAction, SIGNAL(triggered()), this, SLOT(doExit()));
    notloggedmenu->addAction(exitAction);

    openAction=new QAction("Open pCloud folder", this);
    connect(openAction, SIGNAL(triggered()), this, SLOT(openCloudDir()));
    shareFolderAction=new QAction("Share folder", this);
    connect(shareFolderAction, SIGNAL(triggered()), this, SLOT(shareFolder()));
    outgoingSharesAction=new QAction("My Shares", this);
    connect(outgoingSharesAction, SIGNAL(triggered()), this, SLOT(outgoingShares()));
    incomingSharesAction=new QAction("Shared with Me", this);
    connect(incomingSharesAction, SIGNAL(triggered()), this, SLOT(incomingShares()));
    upgradeAction=new QAction("Upgrade", this);
    connect(upgradeAction, SIGNAL(triggered()), this, SLOT(upgradePlan()));

    logoutAction=new QAction("Logout", this);
    connect(logoutAction, SIGNAL(triggered()), this, SLOT(logOut()));
}

PCloudApp::PCloudApp(int &argc, char **argv) :
    QApplication(argc, argv)
{
    reglog=NULL;
    regwin=NULL;
    logwin=NULL;
    loggedmenu=NULL;
    settingswin=NULL;
    sharefolderwin=NULL;
    incomingshareswin=NULL;
    outgoingshareswin=NULL;
    mthread=NULL;
    loggedin=false;
    lastMessageType=0;
    createMenus();
    settings=new PSettings(this);
    tray=new QSystemTrayIcon(this);
    tray->setIcon(QIcon(OFFLINE_ICON));
    tray->setContextMenu(notloggedmenu);
    tray->setToolTip("pCloud");
    connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClicked(QSystemTrayIcon::ActivationReason)));
    connect(tray, SIGNAL(messageClicked()), this, SLOT(trayMsgClicked()));
    connect(this, SIGNAL(logInSignal(QString, QString)), this, SLOT(logIn(QString, QString)));
    connect(this, SIGNAL(showLoginSignal()), this, SLOT(showLogin()));
    tray->show();
    if (settings->isSet("auth") && settings->get("auth").length() > 0){
        othread=new OnlineThread(this);
        othread->start();
    }
    else{
        othread=NULL;
        emit showLoginSignal();
    }
}

PCloudApp::~PCloudApp(){
    if (othread){
        if (othread->isRunning())
            othread->terminate();
        othread->wait();
        delete othread;
    }
    if (mthread){
        if (mthread->isRunning())
            mthread->terminate();
        mthread->wait();
        delete mthread;
    }
    delete settings;
    delete tray;
    if (loggedmenu)
        delete loggedmenu;
    delete notloggedmenu;
    delete registerAction;
    delete loginAction;
    delete exitAction;
    delete logoutAction;
    delete openAction;
    delete settingsAction;
    delete upgradeAction;
    delete shareFolderAction;
    if (regwin)
        delete regwin;
    if (reglog)
        delete reglog;
    if (logwin)
        delete logwin;
    if (settingswin)
        delete settingswin;
    if (sharefolderwin)
        delete sharefolderwin;
    if (incomingshareswin)
        delete incomingshareswin;
    if (outgoingshareswin)
        delete outgoingshareswin;
}

apisock *PCloudApp::getAPISock(){
    if (settings->geti("usessl"))
        return api_connect_ssl();
    else
        return api_connect();
}

bool PCloudApp::isMounted(){
    QDir dir(settings->get("path")+"/.pfs_settings");
    return dir.exists();
}

#ifdef Q_OS_WIN

#define REGISTRY_KEY_PCLOUD    "SOFTWARE\\PCloud\\pCloud"
#define SZSERVICENAME          L"pfs"

static void storeKey(LPCSTR key, const char * val)
{
    HRESULT hr;
    HKEY hKey;
    hr = RegCreateKeyExA(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, NULL, 0,
                        KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if (!hr)
    {
        hr = RegSetValueExA(hKey, key, 0, REG_SZ, (LPBYTE)val, strlen(val)+1);
        RegCloseKey(hKey);
    }
}

static void stopService()
{
    SC_HANDLE       schService;
    SERVICE_STATUS  ssStatus;
    SC_HANDLE       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (!schSCManager) return;
    schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
    if (schService)
    {
        ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus);
        int retry = 5;
        while(QueryServiceStatus(schService, &ssStatus) && retry)
        {
            if (ssStatus.dwCurrentState == SERVICE_STOPPED)
                break;
            Sleep(1000);
            --retry;
        }
        CloseServiceHandle(schService);
    }
    CloseServiceHandle(schSCManager);

}

static bool restartService(QByteArray &err)
{
    SC_HANDLE       schService;
    SERVICE_STATUS  ssStatus;
    SC_HANDLE       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (!schSCManager) return false;
    schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
    if (schService)
    {
        ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus);
        int retry = 5;
        while(QueryServiceStatus(schService, &ssStatus) && retry)
        {
            if (ssStatus.dwCurrentState == SERVICE_STOPPED)
                break;
            Sleep(1000);
            --retry;
        }
        if (!retry){
            err = "Failed to stop PCloud fs.";
        }

        if (StartService(schService, 0, NULL))
        {
            Sleep(1000);
            int retry = 5;
            while(QueryServiceStatus(schService, &ssStatus) && retry)
            {
                --retry;
                if (ssStatus.dwCurrentState == SERVICE_START_PENDING)
                    Sleep(1000);
                else break;
            }
            if (!retry){
                err = "Failed to start PCloud fs.";
                return false;
            }
            else{
                err = "";
                return true;
            }
        }
        CloseServiceHandle(schService);
    }
    CloseServiceHandle(schSCManager);
    return false;
}
#endif

void PCloudApp::mount()
{
    if (settings->isSet("auth")){
        QByteArray auth=settings->get("auth").toUtf8();
        apisock *conn=getAPISock();
        binresult *res, *result;
        QByteArray err;
        if (!conn)
            return;
        res=send_command(conn, "userinfo",
                         P_LSTR("auth", auth.constData(), auth.size()),
                         P_BOOL("getauth", 1));
        api_close(conn);
        result=find_res(res, "result");
        if (!result){
            free(res);
            return;
        }
        if (result->num!=0){
            free(res);
            return;
        }
        userLogged(res, err);
        free(res);
    }
}

void PCloudApp::unMount(){
#ifdef Q_OS_WIN
    stopService();
#else
    QProcess process;
    QString path=settings->get("path");
    process.start("umount", QStringList() << "-f" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
    process.start("fusermount", QStringList() << "-u" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
    process.start("fusermount", QStringList() << "-z" << "-u" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
#endif
}

void PCloudApp::showError(QString err){
    tray->showMessage("Error", err, QSystemTrayIcon::Warning);
}

void PCloudApp::showTrayMessage(QString title, QString msg)
{
    tray->showMessage(title, msg, QSystemTrayIcon::Information);
}

void PCloudApp::logIn(QString auth, QString uname)
{
    settings->set("auth", auth);
#ifdef Q_OS_WIN
    if (!settings->isSet("path") || !settings->get("path").toUtf8()[0]){
        QString path("a:");
        path[0] = getFirstFreeDevice();
        settings->set("path", path);
    }
#endif
    loggedin=true;
    username=uname;
    tray->setToolTip(username);
    if (loggedmenu)
        delete loggedmenu;
    loggedmenu=new QMenu();
    loggedmenu->addAction(username);
    loggedmenu->addAction(openAction);
    loggedmenu->addSeparator();
    loggedmenu->addAction(shareFolderAction);
    loggedmenu->addAction(outgoingSharesAction);
    loggedmenu->addAction(incomingSharesAction);
    loggedmenu->addSeparator();
    loggedmenu->addAction(settingsAction);
    loggedmenu->addSeparator();
    loggedmenu->addAction(upgradeAction);
    loggedmenu->addAction(logoutAction);
    loggedmenu->addAction(exitAction);
    tray->setIcon(QIcon(ONLINE_ICON));
    tray->setContextMenu(loggedmenu);
    if (!mthread){
        mthread=new MonitoringThread(this);
        mthread->start();
    }
}

void PCloudApp::trayMsgClicked()
{
    if (lastMessageType&2)
        outgoingShares();
    else if (lastMessageType)
        incomingShares();
}

void PCloudApp::setOnlineStatus(bool online)
{
    static bool lastStatus = isMounted();
    if (online){
        tray->setIcon(QIcon(ONLINE_ICON));
        if (online != lastStatus) {
            lastMessageType = 0;
            tray->showMessage("PCloud connected", "", QSystemTrayIcon::Information);
            lastStatus = online;
        }
    }
    else{
        tray->setIcon(QIcon(OFFLINE_ICON));
        if (online != lastStatus){
            lastMessageType = 0;
            tray->showMessage("PCloud disconnected", "", QSystemTrayIcon::Information);
            lastStatus = online;
        }
    }
}

bool PCloudApp::userLogged(binresult *userinfo, QByteArray &err){
    if (isMounted()){
        setUser(userinfo);
        return true;
    }
    else{
#ifdef Q_OS_WIN
        if (find_res(userinfo, "auth")){
            if (!settings->isSet("path") || !settings->get("path").toUtf8()[0]){
                QString path("a:");
                path[0] = getFirstFreeDevice();
                settings->set("path", path);
            }
            storeKey("path", settings->get("path").toUtf8());
            storeKey("cachesize", settings->get("cachesize").toUtf8());
            storeKey("ssl", settings->geti("usessl")?"SSL":"");
            storeKey("auth", find_res(userinfo, "auth")->str);
            QString auth(find_res(userinfo, "auth")->str);
            settings->set("auth", auth);
            if (restartService(err)){
                setUser(userinfo);
                return true;
            }
            return false;
        }
        else {
            err = "User not logged in.";
            return false;
        }
#else
        QProcess process;
        QStringList params;
#ifdef Q_OS_MAC
        params.append("-o");
        params.append("volname=pCloud");
        // Adding -o local may or may not be a good idea
        params.append("-o");
        params.append("local");
#endif
        params.append("--auth");
        params.append(find_res(userinfo, "auth")->str);
        if (settings->geti("usessl"))
            params.append("--ssl");
        params.append("--cache");
        params.append(settings->get("cachesize"));
        params.append(settings->get("path"));
#ifdef Q_OS_MAC
        process.start("/usr/local/bin/mount.pfs", params);
#else
        process.start("mount.pfs", params);
#endif
        if (!process.waitForFinished()){
            err="Error mounting filesystem.";
            return false;
        }
        if (process.exitCode()==0){
            setUser(userinfo);
            return true;
        }
        else {
            err=process.readAllStandardError();
            return false;
        }
#endif
    }
}
<commit_msg>try running umount from /sbin<commit_after>#include "pcloudapp.h"
#include "common.h"
#include <QMenu>
#include <QProcess>
#include <QUrl>
#include <QDir>
#include <QDesktopServices>

void PCloudApp::hideAllWindows(){
    if (reglog)
        reglog->hide();
    if (regwin)
        regwin->hide();
    if (logwin)
        logwin->hide();
    if (settingswin)
        settingswin->hide();
    if (incomingshareswin)
        incomingshareswin->hide();
    if (outgoingshareswin)
        outgoingshareswin->hide();
}

void PCloudApp::setUser(binresult *userinfo){
    emit logInSignal(find_res(userinfo, "auth")->str, find_res(userinfo, "email")->str);
}

void PCloudApp::showWindow(QMainWindow *win)
{
    win->raise();
    win->activateWindow();
    win->showNormal();
    win->setWindowState(Qt::WindowActive);
    this->setActiveWindow(win);
}

void PCloudApp::showRegLog(){
    hideAllWindows();
    if (!reglog)
        reglog=new RegLogWindow(this);
    showWindow(reglog);
}

void PCloudApp::showRegister(){
    hideAllWindows();
    if (!regwin)
        regwin=new RegisterWindow(this);
    showWindow(regwin);
}

void PCloudApp::showLogin(){
    hideAllWindows();
    if (!logwin)
        logwin=new LoginWindow(this);
    showWindow(logwin);
}

void PCloudApp::showSettings(){
    hideAllWindows();
    if (!settingswin)
        settingswin=new SettingsWindow(this);
    showWindow(settingswin);
}

void PCloudApp::openCloudDir(){
    QDesktopServices::openUrl(QUrl::fromLocalFile(settings->get("path")));
}

void PCloudApp::shareFolder(){
    hideAllWindows();
    if (!sharefolderwin)
        sharefolderwin=new ShareFolderWindow(this);
    showWindow(sharefolderwin);
}

void PCloudApp::outgoingShares(){
    hideAllWindows();
    if (!outgoingshareswin)
        outgoingshareswin=new SharesWindow(this, 0);
    showWindow(outgoingshareswin);
}

void PCloudApp::incomingShares()
{
    hideAllWindows();
    if (!incomingshareswin)
        incomingshareswin=new SharesWindow(this, 1);
    showWindow(incomingshareswin);
}

void PCloudApp::logOut(){
    loggedin=false;
    username="";
    tray->setContextMenu(notloggedmenu);
    tray->setToolTip("pCloud");
    tray->setIcon(QIcon(OFFLINE_ICON));
    settings->unset("auth");
    unMount();
}

void PCloudApp::upgradePlan()
{
    QUrl url("https://my.pcloud.com/#page=plans&authtoken="+settings->get("auth"));
    QDesktopServices::openUrl(url);
}

void PCloudApp::doExit(){
    unMount();
    quit();
}

void PCloudApp::trayClicked(QSystemTrayIcon::ActivationReason reason){
    if (reason==QSystemTrayIcon::Trigger){
        if (loggedin)
            openCloudDir();
        else
            showLogin();
    }
}

void PCloudApp::createMenus(){
    notloggedmenu=new QMenu();
    registerAction=new QAction("Register", this);
    connect(registerAction, SIGNAL(triggered()), this, SLOT(showRegister()));
    notloggedmenu->addAction(registerAction);
    loginAction=new QAction("Login", this);
    connect(loginAction, SIGNAL(triggered()), this, SLOT(showLogin()));
    notloggedmenu->addAction(loginAction);
    settingsAction=new QAction("Settings", this);
    connect(settingsAction, SIGNAL(triggered()), this, SLOT(showSettings()));
    notloggedmenu->addAction(settingsAction);
    notloggedmenu->addSeparator();
    exitAction=new QAction("Exit", this);
    connect(exitAction, SIGNAL(triggered()), this, SLOT(doExit()));
    notloggedmenu->addAction(exitAction);

    openAction=new QAction("Open pCloud folder", this);
    connect(openAction, SIGNAL(triggered()), this, SLOT(openCloudDir()));
    shareFolderAction=new QAction("Share folder", this);
    connect(shareFolderAction, SIGNAL(triggered()), this, SLOT(shareFolder()));
    outgoingSharesAction=new QAction("My Shares", this);
    connect(outgoingSharesAction, SIGNAL(triggered()), this, SLOT(outgoingShares()));
    incomingSharesAction=new QAction("Shared with Me", this);
    connect(incomingSharesAction, SIGNAL(triggered()), this, SLOT(incomingShares()));
    upgradeAction=new QAction("Upgrade", this);
    connect(upgradeAction, SIGNAL(triggered()), this, SLOT(upgradePlan()));

    logoutAction=new QAction("Logout", this);
    connect(logoutAction, SIGNAL(triggered()), this, SLOT(logOut()));
}

PCloudApp::PCloudApp(int &argc, char **argv) :
    QApplication(argc, argv)
{
    reglog=NULL;
    regwin=NULL;
    logwin=NULL;
    loggedmenu=NULL;
    settingswin=NULL;
    sharefolderwin=NULL;
    incomingshareswin=NULL;
    outgoingshareswin=NULL;
    mthread=NULL;
    loggedin=false;
    lastMessageType=0;
    createMenus();
    settings=new PSettings(this);
    tray=new QSystemTrayIcon(this);
    tray->setIcon(QIcon(OFFLINE_ICON));
    tray->setContextMenu(notloggedmenu);
    tray->setToolTip("pCloud");
    connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClicked(QSystemTrayIcon::ActivationReason)));
    connect(tray, SIGNAL(messageClicked()), this, SLOT(trayMsgClicked()));
    connect(this, SIGNAL(logInSignal(QString, QString)), this, SLOT(logIn(QString, QString)));
    connect(this, SIGNAL(showLoginSignal()), this, SLOT(showLogin()));
    tray->show();
    if (settings->isSet("auth") && settings->get("auth").length() > 0){
        othread=new OnlineThread(this);
        othread->start();
    }
    else{
        othread=NULL;
        emit showLoginSignal();
    }
}

PCloudApp::~PCloudApp(){
    if (othread){
        if (othread->isRunning())
            othread->terminate();
        othread->wait();
        delete othread;
    }
    if (mthread){
        if (mthread->isRunning())
            mthread->terminate();
        mthread->wait();
        delete mthread;
    }
    delete settings;
    delete tray;
    if (loggedmenu)
        delete loggedmenu;
    delete notloggedmenu;
    delete registerAction;
    delete loginAction;
    delete exitAction;
    delete logoutAction;
    delete openAction;
    delete settingsAction;
    delete upgradeAction;
    delete shareFolderAction;
    if (regwin)
        delete regwin;
    if (reglog)
        delete reglog;
    if (logwin)
        delete logwin;
    if (settingswin)
        delete settingswin;
    if (sharefolderwin)
        delete sharefolderwin;
    if (incomingshareswin)
        delete incomingshareswin;
    if (outgoingshareswin)
        delete outgoingshareswin;
}

apisock *PCloudApp::getAPISock(){
    if (settings->geti("usessl"))
        return api_connect_ssl();
    else
        return api_connect();
}

bool PCloudApp::isMounted(){
    QDir dir(settings->get("path")+"/.pfs_settings");
    return dir.exists();
}

#ifdef Q_OS_WIN

#define REGISTRY_KEY_PCLOUD    "SOFTWARE\\PCloud\\pCloud"
#define SZSERVICENAME          L"pfs"

static void storeKey(LPCSTR key, const char * val)
{
    HRESULT hr;
    HKEY hKey;
    hr = RegCreateKeyExA(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, NULL, 0,
                        KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if (!hr)
    {
        hr = RegSetValueExA(hKey, key, 0, REG_SZ, (LPBYTE)val, strlen(val)+1);
        RegCloseKey(hKey);
    }
}

static void stopService()
{
    SC_HANDLE       schService;
    SERVICE_STATUS  ssStatus;
    SC_HANDLE       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (!schSCManager) return;
    schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
    if (schService)
    {
        ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus);
        int retry = 5;
        while(QueryServiceStatus(schService, &ssStatus) && retry)
        {
            if (ssStatus.dwCurrentState == SERVICE_STOPPED)
                break;
            Sleep(1000);
            --retry;
        }
        CloseServiceHandle(schService);
    }
    CloseServiceHandle(schSCManager);

}

static bool restartService(QByteArray &err)
{
    SC_HANDLE       schService;
    SERVICE_STATUS  ssStatus;
    SC_HANDLE       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (!schSCManager) return false;
    schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
    if (schService)
    {
        ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus);
        int retry = 5;
        while(QueryServiceStatus(schService, &ssStatus) && retry)
        {
            if (ssStatus.dwCurrentState == SERVICE_STOPPED)
                break;
            Sleep(1000);
            --retry;
        }
        if (!retry){
            err = "Failed to stop PCloud fs.";
        }

        if (StartService(schService, 0, NULL))
        {
            Sleep(1000);
            int retry = 5;
            while(QueryServiceStatus(schService, &ssStatus) && retry)
            {
                --retry;
                if (ssStatus.dwCurrentState == SERVICE_START_PENDING)
                    Sleep(1000);
                else break;
            }
            if (!retry){
                err = "Failed to start PCloud fs.";
                return false;
            }
            else{
                err = "";
                return true;
            }
        }
        CloseServiceHandle(schService);
    }
    CloseServiceHandle(schSCManager);
    return false;
}
#endif

void PCloudApp::mount()
{
    if (settings->isSet("auth")){
        QByteArray auth=settings->get("auth").toUtf8();
        apisock *conn=getAPISock();
        binresult *res, *result;
        QByteArray err;
        if (!conn)
            return;
        res=send_command(conn, "userinfo",
                         P_LSTR("auth", auth.constData(), auth.size()),
                         P_BOOL("getauth", 1));
        api_close(conn);
        result=find_res(res, "result");
        if (!result){
            free(res);
            return;
        }
        if (result->num!=0){
            free(res);
            return;
        }
        userLogged(res, err);
        free(res);
    }
}

void PCloudApp::unMount(){
#ifdef Q_OS_WIN
    stopService();
#else
    QProcess process;
    QString path=settings->get("path");
    process.start("umount", QStringList() << "-f" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
    process.start("/sbin/umount", QStringList() << "-f" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
    process.start("fusermount", QStringList() << "-u" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
    process.start("fusermount", QStringList() << "-z" << "-u" << path);
    if (process.waitForFinished() && process.exitCode()==0)
        return;
#endif
}

void PCloudApp::showError(QString err){
    tray->showMessage("Error", err, QSystemTrayIcon::Warning);
}

void PCloudApp::showTrayMessage(QString title, QString msg)
{
    tray->showMessage(title, msg, QSystemTrayIcon::Information);
}

void PCloudApp::logIn(QString auth, QString uname)
{
    settings->set("auth", auth);
#ifdef Q_OS_WIN
    if (!settings->isSet("path") || !settings->get("path").toUtf8()[0]){
        QString path("a:");
        path[0] = getFirstFreeDevice();
        settings->set("path", path);
    }
#endif
    loggedin=true;
    username=uname;
    tray->setToolTip(username);
    if (loggedmenu)
        delete loggedmenu;
    loggedmenu=new QMenu();
    loggedmenu->addAction(username);
    loggedmenu->addAction(openAction);
    loggedmenu->addSeparator();
    loggedmenu->addAction(shareFolderAction);
    loggedmenu->addAction(outgoingSharesAction);
    loggedmenu->addAction(incomingSharesAction);
    loggedmenu->addSeparator();
    loggedmenu->addAction(settingsAction);
    loggedmenu->addSeparator();
    loggedmenu->addAction(upgradeAction);
    loggedmenu->addAction(logoutAction);
    loggedmenu->addAction(exitAction);
    tray->setIcon(QIcon(ONLINE_ICON));
    tray->setContextMenu(loggedmenu);
    if (!mthread){
        mthread=new MonitoringThread(this);
        mthread->start();
    }
}

void PCloudApp::trayMsgClicked()
{
    if (lastMessageType&2)
        outgoingShares();
    else if (lastMessageType)
        incomingShares();
}

void PCloudApp::setOnlineStatus(bool online)
{
    static bool lastStatus = isMounted();
    if (online){
        tray->setIcon(QIcon(ONLINE_ICON));
        if (online != lastStatus) {
            lastMessageType = 0;
            tray->showMessage("PCloud connected", "", QSystemTrayIcon::Information);
            lastStatus = online;
        }
    }
    else{
        tray->setIcon(QIcon(OFFLINE_ICON));
        if (online != lastStatus){
            lastMessageType = 0;
            tray->showMessage("PCloud disconnected", "", QSystemTrayIcon::Information);
            lastStatus = online;
        }
    }
}

bool PCloudApp::userLogged(binresult *userinfo, QByteArray &err){
    if (isMounted()){
        setUser(userinfo);
        return true;
    }
    else{
#ifdef Q_OS_WIN
        if (find_res(userinfo, "auth")){
            if (!settings->isSet("path") || !settings->get("path").toUtf8()[0]){
                QString path("a:");
                path[0] = getFirstFreeDevice();
                settings->set("path", path);
            }
            storeKey("path", settings->get("path").toUtf8());
            storeKey("cachesize", settings->get("cachesize").toUtf8());
            storeKey("ssl", settings->geti("usessl")?"SSL":"");
            storeKey("auth", find_res(userinfo, "auth")->str);
            QString auth(find_res(userinfo, "auth")->str);
            settings->set("auth", auth);
            if (restartService(err)){
                setUser(userinfo);
                return true;
            }
            return false;
        }
        else {
            err = "User not logged in.";
            return false;
        }
#else
        QProcess process;
        QStringList params;
#ifdef Q_OS_MAC
        params.append("-o");
        params.append("volname=pCloud");
        // Adding -o local may or may not be a good idea
        params.append("-o");
        params.append("local");
#endif
        params.append("--auth");
        params.append(find_res(userinfo, "auth")->str);
        if (settings->geti("usessl"))
            params.append("--ssl");
        params.append("--cache");
        params.append(settings->get("cachesize"));
        params.append(settings->get("path"));
#ifdef Q_OS_MAC
        process.start("/usr/local/bin/mount.pfs", params);
#else
        process.start("mount.pfs", params);
#endif
        if (!process.waitForFinished()){
            err="Error mounting filesystem.";
            return false;
        }
        if (process.exitCode()==0){
            setUser(userinfo);
            return true;
        }
        else {
            err=process.readAllStandardError();
            return false;
        }
#endif
    }
}
<|endoftext|>


<commit_before>/**
 *  File name: CNewton.cpp
 *
 *  Programmer: Yongqun He
 *  Contact email: yohe@vt.edu
 *  Purpose: This is the .cpp file for the class CNewton.
 *           It is an important approach to solve the steady state solution problem
 *
 */

#include "copasi.h"
#include "CNewton.h"
#include "tnt/lu.h"

//default constructor
CNewton::CNewton()
{
  mModel = NULL;

  mNewtonLimit = DefaultNewtonLimit;
  mSs_nfunction=0;

  mSs_solution = 0;

  mSs_x = NULL;
  mSs_xnew = NULL;
  //  mSs_dxdt = NULL;
  mSs_h = NULL;
  mSs_ipvt = NULL;

  // initialize();
}

// constructor
CNewton::CNewton(C_INT32 anInt)
{
  mModel = NULL;
  mNewtonLimit = anInt;
  mSs_nfunction = 0;
  mSs_solution = 0;

  //initialize();
}

// copy constructor
CNewton::CNewton(const CNewton& source)
{
  mModel = source.mModel;
  mNewtonLimit = source.mNewtonLimit;
  mSs_nfunction = source.mSs_nfunction;
  mSs_solution = source.mSs_solution;

  mSs_x = source.mSs_x;
  mSs_xnew = source.mSs_xnew;
  mSs_dxdt =source.mSs_dxdt;
  mSs_h = source.mSs_h;
  mSs_jacob = source.mSs_jacob;
  mSs_ipvt = source.mSs_ipvt;
}

// initialize pointers
void CNewton::initialize()
{
  cleanup();
  unsigned C_INT32 dim = mModel->getIndMetab();

  mSs_xnew = new C_FLOAT64[dim];
  // mSs_xnew = new C_FLOAT64[dim];
  mSs_dxdt.newsize(dim);
  mSs_h = new C_FLOAT64[dim];
  mSs_ipvt = new C_INT32[dim];

  mSs_jacob.setModel(*mModel);
}

//Y.H.
//set up mSs_x and mSs_x's default values
//they should come from steady state class, though
void CNewton::init_Ss_x(void)
{
  mSs_x = mModel->getInitialNumbers();
}

//Object assignment overloading
CNewton& CNewton::operator=(const CNewton& source)
{
  if(this != &source)
    {
      mModel = source.mModel;
      mNewtonLimit = source.mNewtonLimit;
      mSs_nfunction = source.mSs_nfunction;
      mSs_solution = source.mSs_solution;

      mSs_x = source.mSs_x;
      mSs_xnew = source.mSs_xnew;
      mSs_dxdt =source.mSs_dxdt;
      mSs_h = source.mSs_h;
      mSs_jacob = source.mSs_jacob;
      mSs_ipvt = source.mSs_ipvt;
    }

  return *this;
}

//destructor
CNewton::~CNewton()
{
  cout << "~CNewton " << endl;
}

//set mModel
void CNewton::setModel(CModel * aModel)
{
  mModel = aModel;

  initialize();
}

//get mModel
CModel * CNewton::getModel() const
{
  return mModel;
}

// set mSSRes
void CNewton::setSSRes(C_FLOAT64 aDouble)
{
  mSSRes = aDouble;
}

//get mSSRes
C_FLOAT64 CNewton::getSSRes() const
{
  return mSSRes;
}

// get mSs_xnew
C_FLOAT64 * CNewton::getSs_xnew() const
{
  return mSs_xnew;
}

// get mSs_dxdt
const TNT::Vector < C_FLOAT64 > & CNewton::getSs_dxdt() const
{
  return mSs_dxdt;
}

// set mDerivFactor
void CNewton::setDerivFactor(C_FLOAT64 aDouble)
{
  mDerivFactor = aDouble;
}

// get mDerivFactor
C_FLOAT64 CNewton::getDerivFactor() const
{
  return mDerivFactor;
}

void CNewton::setNewtonLimit(C_INT32 limit) {mNewtonLimit = limit;}

C_INT32  CNewton::getNewtonLimit() const {return mNewtonLimit;}

// set mSs_nfunction
void CNewton::setSs_nfunction(C_INT32 aInt)
{
  mSs_nfunction = aInt;
}

// get mDerivFactor
C_INT32 CNewton::getSs_nfunction() const
{
  return mSs_nfunction;
}

// finds out if current state is a valid steady state
C_INT32 CNewton::isSteadyState( void )
{
  unsigned C_INT32 i, dim = mModel->getIndMetab();
  double maxrate;

  mSs_solution = SS_NOT_FOUND;
  for( i=0; i<dim; i++ )
    if( mSs_x[i] < 0.0 ) return SS_NOT_FOUND;

  //FEval( 0, 0, mSs_x, ss_dxdt );
  mModel->lSODAEval(dim, 0, mSs_xnew, &mSs_dxdt[0] );
  mSs_nfunction++;
  // maxrate = SS_XNorn( ss_dxdt );
  maxrate = xNorm(dim, &mSs_dxdt[0] - 1, 1);

  if( maxrate < mSSRes ) mSs_solution = SS_FOUND;
  return mSs_solution;
}

//similar to SS_Newton() in gepasi except a few modification
//
void CNewton::process(void)
{

  int i,j,k;
  C_FLOAT64 maxrate, nmaxrate;
  C_INT32 info;
  mSs_solution = SS_NOT_FOUND;

  //by Yongqun He
  //get the dimensions of the matrix
  int dim = mModel->getIndMetab();

  //  try
  // {
  //  mModel->lSODAEval(0, 0, mSs_x, mSs_dxdt );
  //changed by Yongqun He
  mModel->lSODAEval(dim, 0, mSs_x, &mSs_dxdt[0] );

  mSs_nfunction++;
  maxrate =xNorm(dim, &mSs_dxdt[0] - 1, 1);
  if( maxrate < mSSRes )
    mSs_solution = SS_FOUND;
  if( mSs_solution == SS_FOUND )
    {
      for( i=0; i<dim; i++ )
	if( mSs_x[i] < 0.0 )
	  {
	    mSs_solution = SS_NOT_FOUND;
	    break;
	  }
    }
  // }
  // finally
  // {
  //}
  if( mSs_solution==SS_FOUND ) return;
  for( k=0; k<mNewtonLimit; k++ )
    {
      //  try
      //{
      //JEval( mSs_x, mSs_jacob );
      mSs_jacob.jacobEval(mSs_x, mDerivFactor, mSSRes);

      /* :TODO: We have to check whether LU is really needed? */
      TNT::Matrix < C_FLOAT64 > LU = mSs_jacob.getJacob();
      TNT::Vector < unsigned C_INT32 > rowLU(dim);

      // LU decomposition of Jacobian
      info = TNT::LU_factor(LU, rowLU);
      // dgefa( mSs_jacob, dim, mSs_ipvt, &info);

      if( info!=0 )
	{
	  // jacobian is singular
	  mSs_solution = SS_SINGULAR_JACOBIAN;

	  return;
	}
      // solve mSs_jacob . x = mSs_h for x (result in mSs_dxdt)
      TNT::LU_solve(LU, rowLU, mSs_dxdt);

      // dgesl( mSs_jacob, mModel->getIndMetab(), mSs_ipvt, mSs_dxdt, 0 );
      // }
      //finally
      //{
      //}
      nmaxrate = maxrate * 1.001;
      // copy values of increment to mSs_h
      for(i=0;i<dim;i++) mSs_h[i] = mSs_dxdt[i];
      for( i=0; (i<32) && (nmaxrate>maxrate) ; i++ )
	{
	  for( j=0; j<dim; j++ )
	    {
	      mSs_xnew[j] = mSs_x[j] - mSs_h[j];
	      mSs_h[j] /= 2;
	    }
	  // this is done inside lSODAEval
	  // mModel->setConcentrations(mSs_xnew);
	  // update the dependent metabolites
	  //  try
	  //{
	  //FEval( 0, 0, mSs_xnew, mSs_dxdt );
	  mModel->lSODAEval(dim, 0, mSs_xnew, &mSs_dxdt[0] );
	  mSs_nfunction++;
	  nmaxrate = xNorm(dim, &mSs_dxdt[0] - 1, 1);
	  //}
	  //finally
	  //{
	  //}
	}
      if( i==32 )
	{
	  if( maxrate < mSSRes )
	    {
	      mSs_solution = SS_FOUND;
	      // check if solution is valid
	      for( i=0; i<mModel->getIntMetab(); i++ )
		if( mSs_x[i] < 0.0 )
		  {
		    mSs_solution = SS_NOT_FOUND;
		    break;
		  }

	      return;
	    }
	  else
	    {
	      mSs_solution = SS_DAMPING_LIMIT;

	      return;
	    }
	}
      for(i=0;i<dim;i++) mSs_x[i] = mSs_xnew[i];
      maxrate = nmaxrate;
    }
  if( maxrate < mSSRes )
    {
      mSs_solution = SS_FOUND;
      // check if solution is valid
      for( i=0; i<dim; i++ )
	if( mSs_x[i] < 0.0 )
	  {
	    mSs_solution = SS_NOT_FOUND;
	    break;
	  }

      return;
    }
  else
    {
      mSs_solution = SS_ITERATION_LIMIT;

      return;
    }

}

// Clean up internal pointer variables
void CNewton::cleanup(void)
{
  if (mSs_x) delete [] mSs_x;
  mSs_x = NULL;

  if (mSs_xnew) delete [] mSs_xnew;
  mSs_xnew = NULL;

  // if (mSs_dxdt) delete [] mSs_dxdt;
  // mSs_dxdt = NULL;

  if (mSs_h) delete [] mSs_h;
  mSs_h = NULL;

  if (mSs_ipvt) delete [] mSs_ipvt;
  mSs_ipvt = NULL;
}

#ifdef XXXX
// evaluates the Jacobian matrix
void CNewton::JEval( double *y, double **ydot )
{
  register int i, j;
  double store, temp, *f1, *f2;
  double K1, K2, K3;
  // constants for differentiation by finite differences
  K1 = 1 + mDerivFactor;
  K2 = 1 - mDerivFactor;
  K3 = 2 * mDerivFactor;
  // arrays to store function values
  f1 = new double[mModel->getIntMetab()+1];
  f2 = new double[mModel->getIntMetab()+1];
  // iterate over all metabolites
  for( i=1; i<mModel->getIndMetab()+1; i++ )
    {
      // if y[i] is zero, the derivative will be calculated at a small
      // positive value (no point in considering negative values!).
      // let's stick with mSSRes*(1.0+mDerivFactor)
      store = y[i];
      if( store < mSSRes ) temp = mSSRes*K1;
      else temp = store;
      y[i] = temp*K1;
      //FEval( 0, 0, y, f1 );
      mModel->lSODAEval(0, 0, y, f1);
      mSs_nfunction++;
      y[i] = temp*K2;
      //FEval( 0, 0, y, f2 );
      mModel->lSODAEval(0, 0, y, f2);
      mSs_nfunction++;
      for( j=1; j<mModel->getIndMetab()+1; j++ )
	ydot[j][i] = (f1[j]-f2[j])/(temp*K3);
      y[i] = store;
    }
  delete [] f1;
  delete [] f2;

  //Yongqun He: no plan to count the JEval() yet. Maybe later.
  //ss_njacob++;
}
#endif // XXXX
<commit_msg>change the isSteadyState() function<commit_after>/**
 *  File name: CNewton.cpp
 *
 *  Programmer: Yongqun He
 *  Contact email: yohe@vt.edu
 *  Purpose: This is the .cpp file for the class CNewton.
 *           It is an important approach to solve the steady state solution problem
 *
 */

#include "copasi.h"
#include "CNewton.h"
#include "tnt/lu.h"

//default constructor
CNewton::CNewton()
{
  mModel = NULL;

  mNewtonLimit = DefaultNewtonLimit;
  mSs_nfunction=0;

  mSs_solution = 0;

  mSs_x = NULL;
  mSs_xnew = NULL;
  //  mSs_dxdt = NULL;
  mSs_h = NULL;
  mSs_ipvt = NULL;

  // initialize();
}

// constructor
CNewton::CNewton(C_INT32 anInt)
{
  mModel = NULL;
  mNewtonLimit = anInt;
  mSs_nfunction = 0;
  mSs_solution = 0;

  //initialize();
}

// copy constructor
CNewton::CNewton(const CNewton& source)
{
  mModel = source.mModel;
  mNewtonLimit = source.mNewtonLimit;
  mSs_nfunction = source.mSs_nfunction;
  mSs_solution = source.mSs_solution;

  mSs_x = source.mSs_x;
  mSs_xnew = source.mSs_xnew;
  mSs_dxdt =source.mSs_dxdt;
  mSs_h = source.mSs_h;
  mSs_jacob = source.mSs_jacob;
  mSs_ipvt = source.mSs_ipvt;
}

// initialize pointers
void CNewton::initialize()
{
  cleanup();
  unsigned C_INT32 dim = mModel->getIndMetab();

  mSs_xnew = new C_FLOAT64[dim];
  // mSs_xnew = new C_FLOAT64[dim];
  mSs_dxdt.newsize(dim);
  mSs_h = new C_FLOAT64[dim];
  mSs_ipvt = new C_INT32[dim];

  mSs_jacob.setModel(*mModel);
}

//Y.H.
//set up mSs_x and mSs_x's default values
//they should come from steady state class, though
void CNewton::init_Ss_x(void)
{
  mSs_x = mModel->getInitialNumbers();
}

//Object assignment overloading
CNewton& CNewton::operator=(const CNewton& source)
{
  if(this != &source)
    {
      mModel = source.mModel;
      mNewtonLimit = source.mNewtonLimit;
      mSs_nfunction = source.mSs_nfunction;
      mSs_solution = source.mSs_solution;

      mSs_x = source.mSs_x;
      mSs_xnew = source.mSs_xnew;
      mSs_dxdt =source.mSs_dxdt;
      mSs_h = source.mSs_h;
      mSs_jacob = source.mSs_jacob;
      mSs_ipvt = source.mSs_ipvt;
    }

  return *this;
}

//destructor
CNewton::~CNewton()
{
  cout << "~CNewton " << endl;
}

//set mModel
void CNewton::setModel(CModel * aModel)
{
  mModel = aModel;

  initialize();
}

//get mModel
CModel * CNewton::getModel() const
{
  return mModel;
}

// set mSSRes
void CNewton::setSSRes(C_FLOAT64 aDouble)
{
  mSSRes = aDouble;
}

//get mSSRes
C_FLOAT64 CNewton::getSSRes() const
{
  return mSSRes;
}

// get mSs_xnew
C_FLOAT64 * CNewton::getSs_xnew() const
{
  return mSs_xnew;
}

// get mSs_dxdt
const TNT::Vector < C_FLOAT64 > & CNewton::getSs_dxdt() const
{
  return mSs_dxdt;
}

// set mDerivFactor
void CNewton::setDerivFactor(C_FLOAT64 aDouble)
{
  mDerivFactor = aDouble;
}

// get mDerivFactor
C_FLOAT64 CNewton::getDerivFactor() const
{
  return mDerivFactor;
}

void CNewton::setNewtonLimit(C_INT32 limit) {mNewtonLimit = limit;}

C_INT32  CNewton::getNewtonLimit() const {return mNewtonLimit;}

// set mSs_nfunction
void CNewton::setSs_nfunction(C_INT32 aInt)
{
  mSs_nfunction = aInt;
}

// get mDerivFactor
C_INT32 CNewton::getSs_nfunction() const
{
  return mSs_nfunction;
}

// finds out if current state is a valid steady state
C_INT32 CNewton::isSteadyState( void )
{
  return mSs_solution;
}

/*

// finds out if current state is a valid steady state
C_INT32 CNewton::isSteadyState( void )
{
  unsigned C_INT32 i, dim = mModel->getIndMetab();
  double maxrate;

  mSs_solution = SS_NOT_FOUND;
  for( i=0; i<dim; i++ )
    if( mSs_x[i] < 0.0 ) return SS_NOT_FOUND;

  //FEval( 0, 0, mSs_x, ss_dxdt );
  mModel->lSODAEval(dim, 0, mSs_xnew, &mSs_dxdt[0] );
  mSs_nfunction++;
  // maxrate = SS_XNorn( ss_dxdt );
  maxrate = xNorm(dim, &mSs_dxdt[0] - 1, 1);

  if( maxrate < mSSRes ) mSs_solution = SS_FOUND;
  return mSs_solution;
}

*/

//similar to SS_Newton() in gepasi except a few modification
//
void CNewton::process(void)
{

  int i,j,k;
  C_FLOAT64 maxrate, nmaxrate;
  C_INT32 info;
  mSs_solution = SS_NOT_FOUND;

  //by Yongqun He
  //get the dimensions of the matrix
  int dim = mModel->getIndMetab();

  //  try
  // {
  //  mModel->lSODAEval(0, 0, mSs_x, mSs_dxdt );
  //changed by Yongqun He
  mModel->lSODAEval(dim, 0, mSs_x, &mSs_dxdt[0] );

  mSs_nfunction++;
  maxrate =xNorm(dim, &mSs_dxdt[0] - 1, 1);
  if( maxrate < mSSRes )
    mSs_solution = SS_FOUND;
  if( mSs_solution == SS_FOUND )
    {
      for( i=0; i<dim; i++ )
	if( mSs_x[i] < 0.0 )
	  {
	    mSs_solution = SS_NOT_FOUND;
	    break;
	  }
    }
  // }
  // finally
  // {
  //}
  if( mSs_solution==SS_FOUND ) return;
  for( k=0; k<mNewtonLimit; k++ )
    {
      //  try
      //{
      //JEval( mSs_x, mSs_jacob );
      mSs_jacob.jacobEval(mSs_x, mDerivFactor, mSSRes);

      /* :TODO: We have to check whether LU is really needed? */
      TNT::Matrix < C_FLOAT64 > LU = mSs_jacob.getJacob();
      TNT::Vector < unsigned C_INT32 > rowLU(dim);

      // LU decomposition of Jacobian
      info = TNT::LU_factor(LU, rowLU);
      // dgefa( mSs_jacob, dim, mSs_ipvt, &info);

      if( info!=0 )
	{
	  // jacobian is singular
	  mSs_solution = SS_SINGULAR_JACOBIAN;

	  return;
	}
      // solve mSs_jacob . x = mSs_h for x (result in mSs_dxdt)
      TNT::LU_solve(LU, rowLU, mSs_dxdt);

      // dgesl( mSs_jacob, mModel->getIndMetab(), mSs_ipvt, mSs_dxdt, 0 );
      // }
      //finally
      //{
      //}
      nmaxrate = maxrate * 1.001;
      // copy values of increment to mSs_h
      for(i=0;i<dim;i++) mSs_h[i] = mSs_dxdt[i];
      for( i=0; (i<32) && (nmaxrate>maxrate) ; i++ )
	{
	  for( j=0; j<dim; j++ )
	    {
	      mSs_xnew[j] = mSs_x[j] - mSs_h[j];
	      mSs_h[j] /= 2;
	    }
	  // this is done inside lSODAEval
	  // mModel->setConcentrations(mSs_xnew);
	  // update the dependent metabolites
	  //  try
	  //{
	  //FEval( 0, 0, mSs_xnew, mSs_dxdt );
	  mModel->lSODAEval(dim, 0, mSs_xnew, &mSs_dxdt[0] );
	  mSs_nfunction++;
	  nmaxrate = xNorm(dim, &mSs_dxdt[0] - 1, 1);
	  //}
	  //finally
	  //{
	  //}
	}
      if( i==32 )
	{
	  if( maxrate < mSSRes )
	    {
	      mSs_solution = SS_FOUND;
	      // check if solution is valid
	      for( i=0; i<mModel->getIntMetab(); i++ )
		if( mSs_x[i] < 0.0 )
		  {
		    mSs_solution = SS_NOT_FOUND;
		    break;
		  }

	      return;
	    }
	  else
	    {
	      mSs_solution = SS_DAMPING_LIMIT;

	      return;
	    }
	}
      for(i=0;i<dim;i++) mSs_x[i] = mSs_xnew[i];
      maxrate = nmaxrate;
    }
  if( maxrate < mSSRes )
    {
      mSs_solution = SS_FOUND;
      // check if solution is valid
      for( i=0; i<dim; i++ )
	if( mSs_x[i] < 0.0 )
	  {
	    mSs_solution = SS_NOT_FOUND;
	    break;
	  }

      return;
    }
  else
    {
      mSs_solution = SS_ITERATION_LIMIT;

      return;
    }

}

// Clean up internal pointer variables
void CNewton::cleanup(void)
{
  if (mSs_x) delete [] mSs_x;
  mSs_x = NULL;

  if (mSs_xnew) delete [] mSs_xnew;
  mSs_xnew = NULL;

  // if (mSs_dxdt) delete [] mSs_dxdt;
  // mSs_dxdt = NULL;

  if (mSs_h) delete [] mSs_h;
  mSs_h = NULL;

  if (mSs_ipvt) delete [] mSs_ipvt;
  mSs_ipvt = NULL;
}

#ifdef XXXX
// evaluates the Jacobian matrix
void CNewton::JEval( double *y, double **ydot )
{
  register int i, j;
  double store, temp, *f1, *f2;
  double K1, K2, K3;
  // constants for differentiation by finite differences
  K1 = 1 + mDerivFactor;
  K2 = 1 - mDerivFactor;
  K3 = 2 * mDerivFactor;
  // arrays to store function values
  f1 = new double[mModel->getIntMetab()+1];
  f2 = new double[mModel->getIntMetab()+1];
  // iterate over all metabolites
  for( i=1; i<mModel->getIndMetab()+1; i++ )
    {
      // if y[i] is zero, the derivative will be calculated at a small
      // positive value (no point in considering negative values!).
      // let's stick with mSSRes*(1.0+mDerivFactor)
      store = y[i];
      if( store < mSSRes ) temp = mSSRes*K1;
      else temp = store;
      y[i] = temp*K1;
      //FEval( 0, 0, y, f1 );
      mModel->lSODAEval(0, 0, y, f1);
      mSs_nfunction++;
      y[i] = temp*K2;
      //FEval( 0, 0, y, f2 );
      mModel->lSODAEval(0, 0, y, f2);
      mSs_nfunction++;
      for( j=1; j<mModel->getIndMetab()+1; j++ )
	ydot[j][i] = (f1[j]-f2[j])/(temp*K3);
      y[i] = store;
    }
  delete [] f1;
  delete [] f2;

  //Yongqun He: no plan to count the JEval() yet. Maybe later.
  //ss_njacob++;
}
#endif // XXXX
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "bindings/core/v8/PrivateScriptRunner.h"

#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8PerContextData.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/PrivateScriptSources.h"
#ifndef NDEBUG
#include "core/PrivateScriptSourcesForTesting.h"
#endif

namespace WebCore {

static v8::Handle<v8::Value> compilePrivateScript(v8::Isolate* isolate, String className)
{
    size_t index;
#ifndef NDEBUG
    for (index = 0; index < WTF_ARRAY_LENGTH(kPrivateScriptSourcesForTesting); index++) {
        if (className == kPrivateScriptSourcesForTesting[index].name)
            break;
    }
    if (index != WTF_ARRAY_LENGTH(kPrivateScriptSourcesForTesting)) {
        String source(reinterpret_cast<const char*>(kPrivateScriptSourcesForTesting[index].source), kPrivateScriptSourcesForTesting[index].size);
        return V8ScriptRunner::compileAndRunInternalScript(v8String(isolate, source), isolate);
    }
#endif

    // |kPrivateScriptSources| is defined in V8PrivateScriptSources.h, which is auto-generated
    // by make_private_script.py.
    for (index = 0; index < WTF_ARRAY_LENGTH(kPrivateScriptSources); index++) {
        if (className == kPrivateScriptSources[index].name)
            break;
    }
    RELEASE_ASSERT(index != WTF_ARRAY_LENGTH(kPrivateScriptSources));
    String source(reinterpret_cast<const char*>(kPrivateScriptSources[index].source), kPrivateScriptSources[index].size);
    return V8ScriptRunner::compileAndRunInternalScript(v8String(isolate, source), isolate);
}

static v8::Handle<v8::Object> classObjectOfPrivateScript(ScriptState* scriptState, String className)
{
    ASSERT(scriptState->perContextData());
    ASSERT(scriptState->executionContext());
    v8::Isolate* isolate = scriptState->isolate();
    v8::Handle<v8::Value> compiledClass = scriptState->perContextData()->compiledPrivateScript(className);
    if (compiledClass.IsEmpty()) {
        v8::Handle<v8::Value> installedClasses = scriptState->perContextData()->compiledPrivateScript("PrivateScriptRunner");
        if (installedClasses.IsEmpty()) {
            installedClasses = compilePrivateScript(isolate, "PrivateScriptRunner");
            scriptState->perContextData()->setCompiledPrivateScript("PrivateScriptRunner", installedClasses);
        }
        RELEASE_ASSERT(!installedClasses.IsEmpty());
        RELEASE_ASSERT(installedClasses->IsObject());

        compilePrivateScript(isolate, className);
        compiledClass = v8::Handle<v8::Object>::Cast(installedClasses)->Get(v8String(isolate, className));
        RELEASE_ASSERT(!compiledClass.IsEmpty());
        RELEASE_ASSERT(compiledClass->IsObject());
        scriptState->perContextData()->setCompiledPrivateScript(className, compiledClass);
    }
    return v8::Handle<v8::Object>::Cast(compiledClass);
}

// FIXME: Replace this method with a V8 API for getOwnPropertyDescriptor, once V8 is rolled.
static v8::Handle<v8::Object> getOwnPropertyDescriptor(ScriptState* scriptState, v8::Handle<v8::Object> classObject, String name)
{
    ASSERT(!scriptState->contextIsEmpty());
    v8::Handle<v8::Value> object = scriptState->context()->Global()->Get(v8String(scriptState->isolate(), "Object"));
    RELEASE_ASSERT(!object.IsEmpty());
    RELEASE_ASSERT(object->IsObject());
    v8::Handle<v8::Value> getOwnPropertyDescriptorFunction = v8::Handle<v8::Object>::Cast(object)->Get(v8String(scriptState->isolate(), "getOwnPropertyDescriptor"));
    RELEASE_ASSERT(!getOwnPropertyDescriptorFunction.IsEmpty());
    RELEASE_ASSERT(getOwnPropertyDescriptorFunction->IsFunction());
    v8::Handle<v8::Value> argv[] = { classObject, v8String(scriptState->isolate(), name) };
    v8::Handle<v8::Value> descriptor = V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function>::Cast(getOwnPropertyDescriptorFunction), object, WTF_ARRAY_LENGTH(argv), argv, scriptState->isolate());
    RELEASE_ASSERT(!descriptor.IsEmpty());
    RELEASE_ASSERT(descriptor->IsObject());
    return v8::Handle<v8::Object>::Cast(descriptor);
}

static void initializeHolderIfNeeded(ScriptState* scriptState, v8::Handle<v8::Object> classObject, v8::Handle<v8::Value> holder)
{
    RELEASE_ASSERT(!holder.IsEmpty());
    RELEASE_ASSERT(holder->IsObject());
    v8::Handle<v8::Object> holderObject = v8::Handle<v8::Object>::Cast(holder);
    v8::Isolate* isolate = scriptState->isolate();
    v8::Handle<v8::Value> isInitialized = V8HiddenValue::getHiddenValue(isolate, holderObject, V8HiddenValue::privateScriptObjectIsInitialized(isolate));
    if (isInitialized.IsEmpty()) {
        v8::Handle<v8::Value> initializeFunction = classObject->Get(v8String(isolate, "constructor"));
        if (!initializeFunction.IsEmpty()) {
            RELEASE_ASSERT(initializeFunction->IsFunction());
            V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(initializeFunction), scriptState->executionContext(), holder, 0, 0, isolate);
            isInitialized = v8Boolean(true, isolate);
            V8HiddenValue::setHiddenValue(isolate, holderObject, V8HiddenValue::privateScriptObjectIsInitialized(isolate), isInitialized);
        }
    }
}

v8::Handle<v8::Value> PrivateScriptRunner::installClass(LocalFrame* frame, String className)
{
    if (!frame)
        return v8::Handle<v8::Value>();
    v8::Handle<v8::Context> context = toV8Context(frame, DOMWrapperWorld::privateScriptIsolatedWorld());
    if (context.IsEmpty())
        return v8::Handle<v8::Value>();
    ScriptState* scriptState = ScriptState::from(context);
    if (!scriptState->executionContext())
        return v8::Handle<v8::Value>();

    ScriptState::Scope scope(scriptState);
    return classObjectOfPrivateScript(scriptState, className);
}

v8::Handle<v8::Value> PrivateScriptRunner::runDOMAttributeGetter(ScriptState* scriptState, String className, String attributeName, v8::Handle<v8::Value> holder)
{
    v8::Handle<v8::Object> classObject = classObjectOfPrivateScript(scriptState, className);
    v8::Handle<v8::Object> descriptor = getOwnPropertyDescriptor(scriptState, classObject, attributeName);
    v8::Handle<v8::Value> getter = descriptor->Get(v8String(scriptState->isolate(), "get"));
    RELEASE_ASSERT(!getter.IsEmpty());
    RELEASE_ASSERT(getter->IsFunction());
    initializeHolderIfNeeded(scriptState, classObject, holder);
    return V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(getter), scriptState->executionContext(), holder, 0, 0, scriptState->isolate());
}

void PrivateScriptRunner::runDOMAttributeSetter(ScriptState* scriptState, String className, String attributeName, v8::Handle<v8::Value> holder, v8::Handle<v8::Value> v8Value)
{
    v8::Handle<v8::Object> classObject = classObjectOfPrivateScript(scriptState, className);
    v8::Handle<v8::Object> descriptor = getOwnPropertyDescriptor(scriptState, classObject, attributeName);
    v8::Handle<v8::Value> setter = descriptor->Get(v8String(scriptState->isolate(), "set"));
    RELEASE_ASSERT(!setter.IsEmpty());
    RELEASE_ASSERT(setter->IsFunction());
    initializeHolderIfNeeded(scriptState, classObject, holder);
    v8::Handle<v8::Value> argv[] = { v8Value };
    V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(setter), scriptState->executionContext(), holder, WTF_ARRAY_LENGTH(argv), argv, scriptState->isolate());
}

v8::Handle<v8::Value> PrivateScriptRunner::runDOMMethod(ScriptState* scriptState, String className, String methodName, v8::Handle<v8::Value> holder, int argc, v8::Handle<v8::Value> argv[])
{
    v8::Handle<v8::Object> classObject = classObjectOfPrivateScript(scriptState, className);
    v8::Handle<v8::Value> method = classObject->Get(v8String(scriptState->isolate(), methodName));
    RELEASE_ASSERT(!method.IsEmpty());
    RELEASE_ASSERT(method->IsFunction());
    initializeHolderIfNeeded(scriptState, classObject, holder);
    return V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(method), scriptState->executionContext(), holder, argc, argv, scriptState->isolate());
}

} // namespace WebCore
<commit_msg>'.constructor' in private scripts should not be called multiple times<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "bindings/core/v8/PrivateScriptRunner.h"

#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8PerContextData.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/PrivateScriptSources.h"
#ifndef NDEBUG
#include "core/PrivateScriptSourcesForTesting.h"
#endif

namespace WebCore {

static v8::Handle<v8::Value> compilePrivateScript(v8::Isolate* isolate, String className)
{
    size_t index;
#ifndef NDEBUG
    for (index = 0; index < WTF_ARRAY_LENGTH(kPrivateScriptSourcesForTesting); index++) {
        if (className == kPrivateScriptSourcesForTesting[index].name)
            break;
    }
    if (index != WTF_ARRAY_LENGTH(kPrivateScriptSourcesForTesting)) {
        String source(reinterpret_cast<const char*>(kPrivateScriptSourcesForTesting[index].source), kPrivateScriptSourcesForTesting[index].size);
        return V8ScriptRunner::compileAndRunInternalScript(v8String(isolate, source), isolate);
    }
#endif

    // |kPrivateScriptSources| is defined in V8PrivateScriptSources.h, which is auto-generated
    // by make_private_script.py.
    for (index = 0; index < WTF_ARRAY_LENGTH(kPrivateScriptSources); index++) {
        if (className == kPrivateScriptSources[index].name)
            break;
    }
    RELEASE_ASSERT(index != WTF_ARRAY_LENGTH(kPrivateScriptSources));
    String source(reinterpret_cast<const char*>(kPrivateScriptSources[index].source), kPrivateScriptSources[index].size);
    return V8ScriptRunner::compileAndRunInternalScript(v8String(isolate, source), isolate);
}

static v8::Handle<v8::Object> classObjectOfPrivateScript(ScriptState* scriptState, String className)
{
    ASSERT(scriptState->perContextData());
    ASSERT(scriptState->executionContext());
    v8::Isolate* isolate = scriptState->isolate();
    v8::Handle<v8::Value> compiledClass = scriptState->perContextData()->compiledPrivateScript(className);
    if (compiledClass.IsEmpty()) {
        v8::Handle<v8::Value> installedClasses = scriptState->perContextData()->compiledPrivateScript("PrivateScriptRunner");
        if (installedClasses.IsEmpty()) {
            installedClasses = compilePrivateScript(isolate, "PrivateScriptRunner");
            scriptState->perContextData()->setCompiledPrivateScript("PrivateScriptRunner", installedClasses);
        }
        RELEASE_ASSERT(!installedClasses.IsEmpty());
        RELEASE_ASSERT(installedClasses->IsObject());

        compilePrivateScript(isolate, className);
        compiledClass = v8::Handle<v8::Object>::Cast(installedClasses)->Get(v8String(isolate, className));
        RELEASE_ASSERT(!compiledClass.IsEmpty());
        RELEASE_ASSERT(compiledClass->IsObject());
        scriptState->perContextData()->setCompiledPrivateScript(className, compiledClass);
    }
    return v8::Handle<v8::Object>::Cast(compiledClass);
}

// FIXME: Replace this method with a V8 API for getOwnPropertyDescriptor, once V8 is rolled.
static v8::Handle<v8::Object> getOwnPropertyDescriptor(ScriptState* scriptState, v8::Handle<v8::Object> classObject, String name)
{
    ASSERT(!scriptState->contextIsEmpty());
    v8::Handle<v8::Value> object = scriptState->context()->Global()->Get(v8String(scriptState->isolate(), "Object"));
    RELEASE_ASSERT(!object.IsEmpty());
    RELEASE_ASSERT(object->IsObject());
    v8::Handle<v8::Value> getOwnPropertyDescriptorFunction = v8::Handle<v8::Object>::Cast(object)->Get(v8String(scriptState->isolate(), "getOwnPropertyDescriptor"));
    RELEASE_ASSERT(!getOwnPropertyDescriptorFunction.IsEmpty());
    RELEASE_ASSERT(getOwnPropertyDescriptorFunction->IsFunction());
    v8::Handle<v8::Value> argv[] = { classObject, v8String(scriptState->isolate(), name) };
    v8::Handle<v8::Value> descriptor = V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function>::Cast(getOwnPropertyDescriptorFunction), object, WTF_ARRAY_LENGTH(argv), argv, scriptState->isolate());
    RELEASE_ASSERT(!descriptor.IsEmpty());
    RELEASE_ASSERT(descriptor->IsObject());
    return v8::Handle<v8::Object>::Cast(descriptor);
}

static void initializeHolderIfNeeded(ScriptState* scriptState, v8::Handle<v8::Object> classObject, v8::Handle<v8::Value> holder)
{
    RELEASE_ASSERT(!holder.IsEmpty());
    RELEASE_ASSERT(holder->IsObject());
    v8::Handle<v8::Object> holderObject = v8::Handle<v8::Object>::Cast(holder);
    v8::Isolate* isolate = scriptState->isolate();
    v8::Handle<v8::Value> isInitialized = V8HiddenValue::getHiddenValue(isolate, holderObject, V8HiddenValue::privateScriptObjectIsInitialized(isolate));
    if (isInitialized.IsEmpty()) {
        v8::Handle<v8::Value> initializeFunction = classObject->Get(v8String(isolate, "constructor"));
        if (!initializeFunction.IsEmpty() && initializeFunction->IsFunction()) {
            V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(initializeFunction), scriptState->executionContext(), holder, 0, 0, isolate);
        }
        isInitialized = v8Boolean(true, isolate);
        V8HiddenValue::setHiddenValue(isolate, holderObject, V8HiddenValue::privateScriptObjectIsInitialized(isolate), isInitialized);
    }
}

v8::Handle<v8::Value> PrivateScriptRunner::installClass(LocalFrame* frame, String className)
{
    if (!frame)
        return v8::Handle<v8::Value>();
    v8::Handle<v8::Context> context = toV8Context(frame, DOMWrapperWorld::privateScriptIsolatedWorld());
    if (context.IsEmpty())
        return v8::Handle<v8::Value>();
    ScriptState* scriptState = ScriptState::from(context);
    if (!scriptState->executionContext())
        return v8::Handle<v8::Value>();

    ScriptState::Scope scope(scriptState);
    return classObjectOfPrivateScript(scriptState, className);
}

v8::Handle<v8::Value> PrivateScriptRunner::runDOMAttributeGetter(ScriptState* scriptState, String className, String attributeName, v8::Handle<v8::Value> holder)
{
    v8::Handle<v8::Object> classObject = classObjectOfPrivateScript(scriptState, className);
    v8::Handle<v8::Object> descriptor = getOwnPropertyDescriptor(scriptState, classObject, attributeName);
    v8::Handle<v8::Value> getter = descriptor->Get(v8String(scriptState->isolate(), "get"));
    RELEASE_ASSERT(!getter.IsEmpty());
    RELEASE_ASSERT(getter->IsFunction());
    initializeHolderIfNeeded(scriptState, classObject, holder);
    return V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(getter), scriptState->executionContext(), holder, 0, 0, scriptState->isolate());
}

void PrivateScriptRunner::runDOMAttributeSetter(ScriptState* scriptState, String className, String attributeName, v8::Handle<v8::Value> holder, v8::Handle<v8::Value> v8Value)
{
    v8::Handle<v8::Object> classObject = classObjectOfPrivateScript(scriptState, className);
    v8::Handle<v8::Object> descriptor = getOwnPropertyDescriptor(scriptState, classObject, attributeName);
    v8::Handle<v8::Value> setter = descriptor->Get(v8String(scriptState->isolate(), "set"));
    RELEASE_ASSERT(!setter.IsEmpty());
    RELEASE_ASSERT(setter->IsFunction());
    initializeHolderIfNeeded(scriptState, classObject, holder);
    v8::Handle<v8::Value> argv[] = { v8Value };
    V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(setter), scriptState->executionContext(), holder, WTF_ARRAY_LENGTH(argv), argv, scriptState->isolate());
}

v8::Handle<v8::Value> PrivateScriptRunner::runDOMMethod(ScriptState* scriptState, String className, String methodName, v8::Handle<v8::Value> holder, int argc, v8::Handle<v8::Value> argv[])
{
    v8::Handle<v8::Object> classObject = classObjectOfPrivateScript(scriptState, className);
    v8::Handle<v8::Value> method = classObject->Get(v8String(scriptState->isolate(), methodName));
    RELEASE_ASSERT(!method.IsEmpty());
    RELEASE_ASSERT(method->IsFunction());
    initializeHolderIfNeeded(scriptState, classObject, holder);
    return V8ScriptRunner::callFunction(v8::Handle<v8::Function>::Cast(method), scriptState->executionContext(), holder, argc, argv, scriptState->isolate());
}

} // namespace WebCore
<|endoftext|>