<commit_before>/**
 * @file   lllogin_test.cpp
 * @author Mark Palange
 * @date   2009-02-26
 * @brief  Tests of lllogin.cpp.
 *
 * $LicenseInfo:firstyear=2009&license=internal$
 * Copyright (c) 2009, Linden Research, Inc.
 * $/LicenseInfo$
 */

// Precompiled header
#include "linden_common.h"
// associated header
#include "../lllogin.h"
// STL headers
// std headers
#include <iostream>
// external library headers
// other Linden headers
#include "llsd.h"
#include "../../../test/lltut.h"
//#define DEBUG_ON
#include "../../../test/debug.h"
#include "llevents.h"
#include "stringize.h"

/*****************************************************************************
*   Helper classes
*****************************************************************************/
// This is a listener to receive results from lllogin.
class LoginListener: public LLEventTrackable
{
	std::string mName;
	LLSD mLastEvent;
    Debug mDebug;
public:
	LoginListener(const std::string& name) :
		mName(name),
        mDebug(stringize(*this))
	{}

	bool call(const LLSD& event)
	{
		mDebug(STRINGIZE("LoginListener called!: " << event));
		mLastEvent = event;
		return false;
	}

    LLBoundListener listenTo(LLEventPump& pump)
    {
        return pump.listen(mName, boost::bind(&LoginListener::call, this, _1));
	}

	LLSD lastEvent() { return mLastEvent; }

    friend std::ostream& operator<<(std::ostream& out, const LoginListener& listener)
    {
        return out << "LoginListener(" << listener.mName << ')';
    }
};

class LLAresListener: public LLEventTrackable
{
	std::string mName;
	LLSD mEvent;
	bool mImmediateResponse;
	bool mMultipleURIResponse;
    Debug mDebug;

public:
	LLAresListener(const std::string& name,
				   bool i = false,
				   bool m = false
				   ) :
		mName(name),
		mImmediateResponse(i),
		mMultipleURIResponse(m),
        mDebug(stringize(*this))
	{}

	bool handle_event(const LLSD& event)
	{
		mDebug(STRINGIZE("LLAresListener called!: " << event));
		mEvent = event;
		if(mImmediateResponse)
		{
			sendReply();
		}
		return false;
	}

	void sendReply()
	{
		if(mEvent["op"].asString() == "rewriteURI")
		{
			LLSD result;
			if(mMultipleURIResponse)
			{
				result.append(LLSD("login.foo.com"));
			}
			result.append(mEvent["uri"]);
			LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
		}
	}

	LLBoundListener listenTo(LLEventPump& pump)
    {
        return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
	}

    friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
    {
        return out << "LLAresListener(" << listener.mName << ')';
    }
};

class LLXMLRPCListener: public LLEventTrackable
{
	std::string mName;
	LLSD mEvent;
	bool mImmediateResponse;
	LLSD mResponse;
    Debug mDebug;

public:
	LLXMLRPCListener(const std::string& name,
					 bool i = false,
					 const LLSD& response = LLSD()
					 ) :
		mName(name),
		mImmediateResponse(i),
		mResponse(response),
        mDebug(stringize(*this))
	{
		if(mResponse.isUndefined())
		{
			mResponse["status"] = "Complete"; // StatusComplete
			mResponse["errorcode"] = 0;
			mResponse["error"] = "dummy response";
			mResponse["transfer_rate"] = 0;
			mResponse["responses"]["login"] = true;
		}
	}

	void setResponse(const LLSD& r)
	{
		mResponse = r;
	}

	bool handle_event(const LLSD& event)
	{
		mDebug(STRINGIZE("LLXMLRPCListener called!: " << event));
		mEvent = event;
		if(mImmediateResponse)
		{
			sendReply();
		}
		return false;
	}

	void sendReply()
	{
		LLEventPumps::instance().obtain(mEvent["reply"]).post(mResponse);
	}

	LLBoundListener listenTo(LLEventPump& pump)
    {
        return pump.listen(mName, boost::bind(&LLXMLRPCListener::handle_event, this, _1));
	}

    friend std::ostream& operator<<(std::ostream& out, const LLXMLRPCListener& listener)
    {
        return out << "LLXMLRPCListener(" << listener.mName << ')';
    }
};

/*****************************************************************************
*   TUT
*****************************************************************************/
namespace tut
{
    struct llviewerlogin_data
    {
		llviewerlogin_data() :
            pumps(LLEventPumps::instance())
		{}
		LLEventPumps& pumps;
	};

    typedef test_group<llviewerlogin_data> llviewerlogin_group;
    typedef llviewerlogin_group::object llviewerlogin_object;
    llviewerlogin_group llviewerlogingrp("llviewerlogin");

    template<> template<>
    void llviewerlogin_object::test<1>()
    {
        DEBUG;
		// Testing login with immediate repsonses from Ares and XMLPRC
		// The response from both requests will come before the post request exits.
		// This tests an edge case of the login state handling.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		bool respond_immediately = true;
		// Have 'dummy ares' repsond immediately.
		LLAresListener dummyLLAres("dummy_llares", respond_immediately);
		dummyLLAres.listenTo(llaresPump);

		// Have dummy XMLRPC respond immediately.
		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;

		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "foo";
		credentials["last"] = "bar";
		credentials["passwd"] = "secret";

		login.connect("login.bar.com", credentials);

		ensure_equals("Online state", listener.lastEvent()["state"].asString(), "online");
	}

    template<> template<>
    void llviewerlogin_object::test<2>()
    {
        DEBUG;
		// Tests a successful login in with delayed responses.
		// Also includes 'failure' that cause the login module
		// To re-attempt connection, once from a basic failure
		// and once from the 'indeterminate' response.

		set_test_name("LLLogin multiple srv uris w/ success");

		// Testing normal login procedure.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		bool respond_immediately = false;
		bool multiple_addresses = true;
		LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
		dummyLLAres.listenTo(llaresPump);

		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;

		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "foo";
		credentials["last"] = "bar";
		credentials["passwd"] = "secret";

		login.connect("login.bar.com", credentials);

		ensure_equals("SRV state", listener.lastEvent()["state"].asString(), "srvrequest");

		dummyLLAres.sendReply();

		// Test Authenticating State prior to first response.
		ensure_equals("Auth state 1", listener.lastEvent()["state"].asString(), "authenticating");
		ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
		ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com");

		// First send emulated LLXMLRPCListener failure,
		// this should return login to the authenticating step and increase the attempt
		// count.
		LLSD data;
		data["status"] = "OtherError";
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Fail back to authenticate 1", listener.lastEvent()["state"].asString(), "authenticating");
		ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2);
		ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");

		// Now send the 'indeterminate' response.
		data.clear();
		data["status"] = "Complete"; // StatusComplete
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		data["responses"]["login"] = "indeterminate";
		data["next_url"] = "login.indeterminate.com";
		data["next_method"] = "test_login_method";
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Fail back to authenticate 2", listener.lastEvent()["state"].asString(), "authenticating");
		ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
		ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");

		// Finally let the auth succeed.
		data.clear();
		data["status"] = "Complete"; // StatusComplete
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		data["responses"]["login"] = "true";
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");

		login.disconnect();

		ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
	}

    template<> template<>
    void llviewerlogin_object::test<3>()
    {
        DEBUG;
		// Test completed response, that fails to login.
		set_test_name("LLLogin valid response, failure (eg. bad credentials)");

		// Testing normal login procedure.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		LLAresListener dummyLLAres("dummy_llares");
		dummyLLAres.listenTo(llaresPump);

		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;
		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "who";
		credentials["last"] = "what";
		credentials["passwd"] = "badpasswd";

		login.connect("login.bar.com", credentials);

		ensure_equals("SRV state", listener.lastEvent()["state"].asString(), "srvrequest");

		dummyLLAres.sendReply();

		ensure_equals("Auth state", listener.lastEvent()["state"].asString(), "authenticating");

		// Send the failed auth request reponse
		LLSD data;
		data["status"] = "Complete";
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		data["responses"]["login"] = "false";
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
	}

    template<> template<>
    void llviewerlogin_object::test<4>()
    {
        DEBUG;
		// Test incomplete response, that end the attempt.
		set_test_name("LLLogin valid response, failure (eg. bad credentials)");

		// Testing normal login procedure.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		LLAresListener dummyLLAres("dummy_llares");
		dummyLLAres.listenTo(llaresPump);

		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;
		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "these";
		credentials["last"] = "don't";
		credentials["passwd"] = "matter";

		login.connect("login.bar.com", credentials);

		ensure_equals("SRV state", listener.lastEvent()["state"].asString(), "srvrequest");

		dummyLLAres.sendReply();

		ensure_equals("Auth state", listener.lastEvent()["state"].asString(), "authenticating");

		// Send the failed auth request reponse
		LLSD data;
		data["status"] = "OtherError";
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
	}
}
<commit_msg>DEV-32777: tip won't even build on Windows without pacifying MSVC warning<commit_after>/**
 * @file   lllogin_test.cpp
 * @author Mark Palange
 * @date   2009-02-26
 * @brief  Tests of lllogin.cpp.
 *
 * $LicenseInfo:firstyear=2009&license=internal$
 * Copyright (c) 2009, Linden Research, Inc.
 * $/LicenseInfo$
 */

#if LL_WINDOWS
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
#endif

// Precompiled header
#include "linden_common.h"
// associated header
#include "../lllogin.h"
// STL headers
// std headers
#include <iostream>
// external library headers
// other Linden headers
#include "llsd.h"
#include "../../../test/lltut.h"
//#define DEBUG_ON
#include "../../../test/debug.h"
#include "llevents.h"
#include "stringize.h"

/*****************************************************************************
*   Helper classes
*****************************************************************************/
// This is a listener to receive results from lllogin.
class LoginListener: public LLEventTrackable
{
	std::string mName;
	LLSD mLastEvent;
    Debug mDebug;
public:
	LoginListener(const std::string& name) :
		mName(name),
        mDebug(stringize(*this))
	{}

	bool call(const LLSD& event)
	{
		mDebug(STRINGIZE("LoginListener called!: " << event));
		mLastEvent = event;
		return false;
	}

    LLBoundListener listenTo(LLEventPump& pump)
    {
        return pump.listen(mName, boost::bind(&LoginListener::call, this, _1));
	}

	LLSD lastEvent() { return mLastEvent; }

    friend std::ostream& operator<<(std::ostream& out, const LoginListener& listener)
    {
        return out << "LoginListener(" << listener.mName << ')';
    }
};

class LLAresListener: public LLEventTrackable
{
	std::string mName;
	LLSD mEvent;
	bool mImmediateResponse;
	bool mMultipleURIResponse;
    Debug mDebug;

public:
	LLAresListener(const std::string& name,
				   bool i = false,
				   bool m = false
				   ) :
		mName(name),
		mImmediateResponse(i),
		mMultipleURIResponse(m),
        mDebug(stringize(*this))
	{}

	bool handle_event(const LLSD& event)
	{
		mDebug(STRINGIZE("LLAresListener called!: " << event));
		mEvent = event;
		if(mImmediateResponse)
		{
			sendReply();
		}
		return false;
	}

	void sendReply()
	{
		if(mEvent["op"].asString() == "rewriteURI")
		{
			LLSD result;
			if(mMultipleURIResponse)
			{
				result.append(LLSD("login.foo.com"));
			}
			result.append(mEvent["uri"]);
			LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
		}
	}

	LLBoundListener listenTo(LLEventPump& pump)
    {
        return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
	}

    friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
    {
        return out << "LLAresListener(" << listener.mName << ')';
    }
};

class LLXMLRPCListener: public LLEventTrackable
{
	std::string mName;
	LLSD mEvent;
	bool mImmediateResponse;
	LLSD mResponse;
    Debug mDebug;

public:
	LLXMLRPCListener(const std::string& name,
					 bool i = false,
					 const LLSD& response = LLSD()
					 ) :
		mName(name),
		mImmediateResponse(i),
		mResponse(response),
        mDebug(stringize(*this))
	{
		if(mResponse.isUndefined())
		{
			mResponse["status"] = "Complete"; // StatusComplete
			mResponse["errorcode"] = 0;
			mResponse["error"] = "dummy response";
			mResponse["transfer_rate"] = 0;
			mResponse["responses"]["login"] = true;
		}
	}

	void setResponse(const LLSD& r)
	{
		mResponse = r;
	}

	bool handle_event(const LLSD& event)
	{
		mDebug(STRINGIZE("LLXMLRPCListener called!: " << event));
		mEvent = event;
		if(mImmediateResponse)
		{
			sendReply();
		}
		return false;
	}

	void sendReply()
	{
		LLEventPumps::instance().obtain(mEvent["reply"]).post(mResponse);
	}

	LLBoundListener listenTo(LLEventPump& pump)
    {
        return pump.listen(mName, boost::bind(&LLXMLRPCListener::handle_event, this, _1));
	}

    friend std::ostream& operator<<(std::ostream& out, const LLXMLRPCListener& listener)
    {
        return out << "LLXMLRPCListener(" << listener.mName << ')';
    }
};

/*****************************************************************************
*   TUT
*****************************************************************************/
namespace tut
{
    struct llviewerlogin_data
    {
		llviewerlogin_data() :
            pumps(LLEventPumps::instance())
		{}
		LLEventPumps& pumps;
	};

    typedef test_group<llviewerlogin_data> llviewerlogin_group;
    typedef llviewerlogin_group::object llviewerlogin_object;
    llviewerlogin_group llviewerlogingrp("llviewerlogin");

    template<> template<>
    void llviewerlogin_object::test<1>()
    {
        DEBUG;
		// Testing login with immediate repsonses from Ares and XMLPRC
		// The response from both requests will come before the post request exits.
		// This tests an edge case of the login state handling.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		bool respond_immediately = true;
		// Have 'dummy ares' repsond immediately.
		LLAresListener dummyLLAres("dummy_llares", respond_immediately);
		dummyLLAres.listenTo(llaresPump);

		// Have dummy XMLRPC respond immediately.
		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;

		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "foo";
		credentials["last"] = "bar";
		credentials["passwd"] = "secret";

		login.connect("login.bar.com", credentials);

		ensure_equals("Online state", listener.lastEvent()["state"].asString(), "online");
	}

    template<> template<>
    void llviewerlogin_object::test<2>()
    {
        DEBUG;
		// Tests a successful login in with delayed responses.
		// Also includes 'failure' that cause the login module
		// To re-attempt connection, once from a basic failure
		// and once from the 'indeterminate' response.

		set_test_name("LLLogin multiple srv uris w/ success");

		// Testing normal login procedure.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		bool respond_immediately = false;
		bool multiple_addresses = true;
		LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
		dummyLLAres.listenTo(llaresPump);

		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;

		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "foo";
		credentials["last"] = "bar";
		credentials["passwd"] = "secret";

		login.connect("login.bar.com", credentials);

		ensure_equals("SRV state", listener.lastEvent()["state"].asString(), "srvrequest");

		dummyLLAres.sendReply();

		// Test Authenticating State prior to first response.
		ensure_equals("Auth state 1", listener.lastEvent()["state"].asString(), "authenticating");
		ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
		ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com");

		// First send emulated LLXMLRPCListener failure,
		// this should return login to the authenticating step and increase the attempt
		// count.
		LLSD data;
		data["status"] = "OtherError";
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Fail back to authenticate 1", listener.lastEvent()["state"].asString(), "authenticating");
		ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2);
		ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");

		// Now send the 'indeterminate' response.
		data.clear();
		data["status"] = "Complete"; // StatusComplete
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		data["responses"]["login"] = "indeterminate";
		data["next_url"] = "login.indeterminate.com";
		data["next_method"] = "test_login_method";
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Fail back to authenticate 2", listener.lastEvent()["state"].asString(), "authenticating");
		ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
		ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");

		// Finally let the auth succeed.
		data.clear();
		data["status"] = "Complete"; // StatusComplete
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		data["responses"]["login"] = "true";
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");

		login.disconnect();

		ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
	}

    template<> template<>
    void llviewerlogin_object::test<3>()
    {
        DEBUG;
		// Test completed response, that fails to login.
		set_test_name("LLLogin valid response, failure (eg. bad credentials)");

		// Testing normal login procedure.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		LLAresListener dummyLLAres("dummy_llares");
		dummyLLAres.listenTo(llaresPump);

		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;
		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "who";
		credentials["last"] = "what";
		credentials["passwd"] = "badpasswd";

		login.connect("login.bar.com", credentials);

		ensure_equals("SRV state", listener.lastEvent()["state"].asString(), "srvrequest");

		dummyLLAres.sendReply();

		ensure_equals("Auth state", listener.lastEvent()["state"].asString(), "authenticating");

		// Send the failed auth request reponse
		LLSD data;
		data["status"] = "Complete";
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		data["responses"]["login"] = "false";
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
	}

    template<> template<>
    void llviewerlogin_object::test<4>()
    {
        DEBUG;
		// Test incomplete response, that end the attempt.
		set_test_name("LLLogin valid response, failure (eg. bad credentials)");

		// Testing normal login procedure.
		LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
		LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump

		LLAresListener dummyLLAres("dummy_llares");
		dummyLLAres.listenTo(llaresPump);

		LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
		dummyXMLRPC.listenTo(xmlrpcPump);

		LLLogin login;
		LoginListener listener("test_ear");
		listener.listenTo(login.getEventPump());

		LLSD credentials;
		credentials["first"] = "these";
		credentials["last"] = "don't";
		credentials["passwd"] = "matter";

		login.connect("login.bar.com", credentials);

		ensure_equals("SRV state", listener.lastEvent()["state"].asString(), "srvrequest");

		dummyLLAres.sendReply();

		ensure_equals("Auth state", listener.lastEvent()["state"].asString(), "authenticating");

		// Send the failed auth request reponse
		LLSD data;
		data["status"] = "OtherError";
		data["errorcode"] = 0;
		data["error"] = "dummy response";
		data["transfer_rate"] = 0;
		dummyXMLRPC.setResponse(data);
		dummyXMLRPC.sendReply();

		ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
	}
}
<|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 "ui/ozone/platform/egl/egl_surface_factory.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/ozone/public/surface_ozone_egl.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
#include "base/logging.h"

#include "egl_wrapper.h"

#ifndef GL_BGRA_EXT
 #define GL_BGRA_EXT 0x80E1
#endif

#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h>   /* For open(), creat() */
#include <linux/fb.h>
#include <sys/ioctl.h>

#define OZONE_EGL_WINDOW_WIDTH 1024
#define OZONE_EGL_WINDOW_HEIGTH 768

namespace ui {

class EglOzoneCanvas: public ui::SurfaceOzoneCanvas {
 public:
  EglOzoneCanvas();
  virtual ~EglOzoneCanvas();
  // SurfaceOzoneCanvas overrides:
  virtual void ResizeCanvas(const gfx::Size& viewport_size) override;
  virtual skia::RefPtr<SkCanvas> GetCanvas() override {
    return skia::SharePtr<SkCanvas>(surface_->getCanvas());
  }
  virtual void PresentCanvas(const gfx::Rect& damage) override;

  virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }

 private:
  skia::RefPtr<SkSurface> surface_;
  ozone_egl_UserData userDate_;
};

EglOzoneCanvas::EglOzoneCanvas()
{
    memset(&userDate_,0,sizeof(userDate_));
}
EglOzoneCanvas::~EglOzoneCanvas()
{
    ozone_egl_textureShutDown (&userDate_);
}

void EglOzoneCanvas::ResizeCanvas(const gfx::Size& viewport_size)
{
  if(userDate_.width == viewport_size.width() && userDate_.height==viewport_size.height())
  {
      return;
  }
  else if(userDate_.width != 0 && userDate_.height !=0)
  {
      ozone_egl_textureShutDown (&userDate_);
  }
  surface_ = skia::AdoptRef(SkSurface::NewRaster(
        SkImageInfo::Make(viewport_size.width(),
                                   viewport_size.height(),
                                   kN32_SkColorType,
                                   kPremul_SkAlphaType)));
  userDate_.width = viewport_size.width();
  userDate_.height = viewport_size.height();
  userDate_.colorType = GL_BGRA_EXT;
  ozone_egl_textureInit ( &userDate_);
}

void EglOzoneCanvas::PresentCanvas(const gfx::Rect& damage)
{
    SkImageInfo info;
    size_t row_bytes;
    userDate_.data = (char *) surface_->peekPixels(&info, &row_bytes);
    ozone_egl_textureDraw(&userDate_);
    ozone_egl_swap();
}

class OzoneEgl : public ui::SurfaceOzoneEGL {
 public:
  OzoneEgl(gfx::AcceleratedWidget window_id){
     native_window_ = window_id;
  }
  virtual ~OzoneEgl() {
     native_window_=0;
  }

  virtual intptr_t GetNativeWindow() override
  {
    return native_window_;
  }

  virtual bool OnSwapBuffers() override
  {
    return true;
  }

  virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) override {
    return true;
  }

  virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }

 private:
  intptr_t native_window_;
};

SurfaceFactoryEgl::SurfaceFactoryEgl():init_(false)
{

}

SurfaceFactoryEgl::~SurfaceFactoryEgl()
{
    DestroySingleWindow();
}

EGLint g_width;
EGLint g_height;
bool SurfaceFactoryEgl::CreateSingleWindow()
{
  struct fb_var_screeninfo fb_var;

  int fb_fd =  open("/dev/fb0", O_RDWR);

  if(init_)
  {
     return true;
  }

  if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var)) {
        LOG(FATAL) << "failed to get fb var info errno: " << errno;
        g_width = 640;
	g_height = 480;
  } else {
    g_width = fb_var.xres;
    g_height = fb_var.yres;
  }

 close(fb_fd);

 if(!ozone_egl_setup(0, 0, g_width, g_height))
  {
      LOG(FATAL) << "CreateSingleWindow";
      return false;
  }
  init_ = true;
  return true;
}

void SurfaceFactoryEgl::DestroySingleWindow() {
  ozone_egl_destroy();
  init_ = false;
}

intptr_t SurfaceFactoryEgl::GetNativeDisplay() {
  return (intptr_t)ozone_egl_getNativedisp();
}

//gfx::AcceleratedWidget SurfaceFactoryEgl::GetAcceleratedWidget() {
//  if (!CreateSingleWindow())
//    LOG(FATAL) << "failed to create window";
//  return (gfx::AcceleratedWidget)GetNativeDisplay();
//}

scoped_ptr<ui::SurfaceOzoneEGL>
SurfaceFactoryEgl::CreateEGLSurfaceForWidget(
    gfx::AcceleratedWidget widget) {
  return make_scoped_ptr<ui::SurfaceOzoneEGL>(
      new OzoneEgl(widget));
}

bool SurfaceFactoryEgl::LoadEGLGLES2Bindings(
    AddGLLibraryCallback add_gl_library,
    SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
  return false;
}

const int32* SurfaceFactoryEgl::GetEGLSurfaceProperties(
    const int32* desired_list) {
  return ozone_egl_getConfigAttribs();
}

scoped_ptr<ui::SurfaceOzoneCanvas> SurfaceFactoryEgl::CreateCanvasForWidget(
      gfx::AcceleratedWidget widget){
    LOG(ERROR) << "-CreateCanvasForWidget-";
  scoped_ptr<EglOzoneCanvas> canvas(new EglOzoneCanvas());
  return canvas.PassAs<ui::SurfaceOzoneCanvas>();
}

}  // namespace ui
<commit_msg>commenting out getcanvas<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 "ui/ozone/platform/egl/egl_surface_factory.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/ozone/public/surface_ozone_egl.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
#include "base/logging.h"

#include "egl_wrapper.h"

#ifndef GL_BGRA_EXT
 #define GL_BGRA_EXT 0x80E1
#endif

#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h>   /* For open(), creat() */
#include <linux/fb.h>
#include <sys/ioctl.h>

#define OZONE_EGL_WINDOW_WIDTH 1024
#define OZONE_EGL_WINDOW_HEIGTH 768

namespace ui {

class EglOzoneCanvas: public ui::SurfaceOzoneCanvas {
 public:
  EglOzoneCanvas();
  virtual ~EglOzoneCanvas();
  // SurfaceOzoneCanvas overrides:
  virtual void ResizeCanvas(const gfx::Size& viewport_size) override;
  //virtual skia::RefPtr<SkCanvas> GetCanvas() override {
  //  return skia::SharePtr<SkCanvas>(surface_->getCanvas());
  //}
  virtual void PresentCanvas(const gfx::Rect& damage) override;

  virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }

 private:
  skia::RefPtr<SkSurface> surface_;
  ozone_egl_UserData userDate_;
};

EglOzoneCanvas::EglOzoneCanvas()
{
    memset(&userDate_,0,sizeof(userDate_));
}
EglOzoneCanvas::~EglOzoneCanvas()
{
    ozone_egl_textureShutDown (&userDate_);
}

void EglOzoneCanvas::ResizeCanvas(const gfx::Size& viewport_size)
{
  if(userDate_.width == viewport_size.width() && userDate_.height==viewport_size.height())
  {
      return;
  }
  else if(userDate_.width != 0 && userDate_.height !=0)
  {
      ozone_egl_textureShutDown (&userDate_);
  }
  surface_ = skia::AdoptRef(SkSurface::NewRaster(
        SkImageInfo::Make(viewport_size.width(),
                                   viewport_size.height(),
                                   kN32_SkColorType,
                                   kPremul_SkAlphaType)));
  userDate_.width = viewport_size.width();
  userDate_.height = viewport_size.height();
  userDate_.colorType = GL_BGRA_EXT;
  ozone_egl_textureInit ( &userDate_);
}

void EglOzoneCanvas::PresentCanvas(const gfx::Rect& damage)
{
    SkImageInfo info;
    size_t row_bytes;
    userDate_.data = (char *) surface_->peekPixels(&info, &row_bytes);
    ozone_egl_textureDraw(&userDate_);
    ozone_egl_swap();
}

class OzoneEgl : public ui::SurfaceOzoneEGL {
 public:
  OzoneEgl(gfx::AcceleratedWidget window_id){
     native_window_ = window_id;
  }
  virtual ~OzoneEgl() {
     native_window_=0;
  }

  virtual intptr_t GetNativeWindow() override
  {
    return native_window_;
  }

  virtual bool OnSwapBuffers() override
  {
    return true;
  }

  virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) override {
    return true;
  }

  virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }

 private:
  intptr_t native_window_;
};

SurfaceFactoryEgl::SurfaceFactoryEgl():init_(false)
{

}

SurfaceFactoryEgl::~SurfaceFactoryEgl()
{
    DestroySingleWindow();
}

EGLint g_width;
EGLint g_height;
bool SurfaceFactoryEgl::CreateSingleWindow()
{
  struct fb_var_screeninfo fb_var;

  int fb_fd =  open("/dev/fb0", O_RDWR);

  if(init_)
  {
     return true;
  }

  if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var)) {
        LOG(FATAL) << "failed to get fb var info errno: " << errno;
        g_width = 640;
	g_height = 480;
  } else {
    g_width = fb_var.xres;
    g_height = fb_var.yres;
  }

 close(fb_fd);

 if(!ozone_egl_setup(0, 0, g_width, g_height))
  {
      LOG(FATAL) << "CreateSingleWindow";
      return false;
  }
  init_ = true;
  return true;
}

void SurfaceFactoryEgl::DestroySingleWindow() {
  ozone_egl_destroy();
  init_ = false;
}

intptr_t SurfaceFactoryEgl::GetNativeDisplay() {
  return (intptr_t)ozone_egl_getNativedisp();
}

//gfx::AcceleratedWidget SurfaceFactoryEgl::GetAcceleratedWidget() {
//  if (!CreateSingleWindow())
//    LOG(FATAL) << "failed to create window";
//  return (gfx::AcceleratedWidget)GetNativeDisplay();
//}

scoped_ptr<ui::SurfaceOzoneEGL>
SurfaceFactoryEgl::CreateEGLSurfaceForWidget(
    gfx::AcceleratedWidget widget) {
  return make_scoped_ptr<ui::SurfaceOzoneEGL>(
      new OzoneEgl(widget));
}

bool SurfaceFactoryEgl::LoadEGLGLES2Bindings(
    AddGLLibraryCallback add_gl_library,
    SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
  return false;
}

const int32* SurfaceFactoryEgl::GetEGLSurfaceProperties(
    const int32* desired_list) {
  return ozone_egl_getConfigAttribs();
}

scoped_ptr<ui::SurfaceOzoneCanvas> SurfaceFactoryEgl::CreateCanvasForWidget(
      gfx::AcceleratedWidget widget){
    LOG(ERROR) << "-CreateCanvasForWidget-";
  scoped_ptr<EglOzoneCanvas> canvas(new EglOzoneCanvas());
  return canvas.PassAs<ui::SurfaceOzoneCanvas>();
}

}  // namespace ui
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2013, Stuart W Baker
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
 *
 * \file NMRAnetVelocity.hxx
 * This file provides an implementation of velocity in NMRAnet terms.
 *
 * @author Stuart W. Baker
 * @date 2 August 2013
 */

#ifndef _NMRAnetVelocity_hxx_
#define _NMRAnetVelocity_hxx_

#include <cmath>
#include <cstdint>

#include "utils/macros.h"

extern "C" {
/* These come from the ieeehalfprecision.c */
int singles2halfp(void *target, void *source, int numel);
int halfp2singles(void *target, void *source, int numel);
}

/** Conversion factor for MPH. */
#define MPH_FACTOR 0.44704F

/** This type represents how velocity is seen on the wire (16 bit float).
 */
typedef uint16_t float16_t;

namespace NMRAnet
{

/** This class provides a mechanism for working with velocity in different
 *  forms.  A single precision floating point value is used internally to store
 *  velocity, but this class provides the ability to easily work with
 *  different velocity formats including DCC 14/28/128 speed step formats.
 *  NMRAnet velocity is represented as a floating point meters/sec.  The sign
 *  represents direction where negative is reverse and positive is forward.
 *  Sign is always preserved even when the result is 0.  For example,
 *  -7.0 + 7.0 = -0.0 and 7.0 - 7.0 = +0.0  Be careful thought, per the C
 *  standards, a negative zero (-.0.0) velocity compared to constant 0.0 will
 *  compare true.  Always use @ref direction() when trying to determine the
 *  sign or direction of travel.
 */
class Velocity
{
public:
    /** define an enumeration for direction
     */
    enum
    {
        FORWARD  = 0, /**< forward direction */
        POSITIVE = 0, /**< forward direction */
        REVERSE  = 1, /**< reverse direction */
        NEGATIVE = 1, /**< reverse direction */
    };

    /** Default constructor.
     */
    Velocity()
        : velocity(0)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(int value)
        : velocity(value)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(unsigned int value)
        : velocity(value)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(float value)
        : velocity(value)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(double value)
        : velocity(value)
    {
    }

    /** Constructor that takes the 16 bit wire format
     * @param value starting value for Velocity as IEEE half precision float.
     */
    Velocity(float16_t value)
        : velocity(halfp2singles(&velocity, &value, 1))
    {
    }

    /** Copy constructor. */
    Velocity(const Velocity& old_velocity)
        : velocity(old_velocity.velocity)
    {
    }

    /** Destructor does nothing. */
    ~Velocity() {}

    /** Return the speed independent of direction.
     * @return speed absolute value of velocity
     */
    float speed()
    {
        return fabsf(velocity);
    }

    /** Return the direction independent of speed.
     * @return direction FORWARD or REVERSE
     */
    int direction()
    {
        if (std::signbit(velocity))
        {
            return REVERSE;
        }
        return FORWARD;
    }

    void set_direction(int direction)
    {
        switch (direction)
        {
        case FORWARD:
            forward();
            break;
        case REVERSE:
            reverse();
            break;
        default:
            DIE("Unexpected direction value");
        }
    }

    /** Set the direction to forward. */
    void forward()
    {
        if (std::signbit(velocity))
        {
            velocity = -velocity;
        }
    }

    /** Set the direction to reverse. */
    void reverse()
    {
        if (!std::signbit(velocity))
        {
            velocity = -velocity;
        }
    }

    /** Convert the native meters/sec representation into mile per hour.
     * @return velocity represented as miles per hour
     */
    float mph()
    {
        return zero_adjust(velocity * MPH_FACTOR, velocity);
    }

    /** Get the speed in DCC 128 speed step format.
     *  The mapping from meters/sec is strait forward.  First convert to
     *  miles/hour, then each speed step represents 1 mile/hour.  Saturate at
     *  126 miles/hour.
     *
     *  bit 7:  direction
     *  bits 6..0:  0 = stopped, 1 = estop, 2 - 127 = speed steps 1 - 126
     *  @return DCC encoded speed steps
     */
    uint8_t get_dcc_128();

    /** Set the speed from DCC 128 speed step format.
     *  The mapping from meters/sec is strait forward.  First convert to
     *  miles/hour, then each speed step represents 1 mile/hour.  Saturate at
     *  126 miles/hour.
     *
     *  @param value bit 7:  direction
     *               bits 6..0:  0 = stopped, 1 = estop, 2 - 127 = speed steps 1 - 126
     */
    void set_dcc_128(uint8_t value);

    /** Get the speed in DCC 28 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  bit 7..6:  fixed at b'01'
     *  bit 5:  direction
     *  bits 4:  speed step least significant bit
     *  bits 3..0:  speed step significatn bits 4..1
     *  @return DCC encoded speed steps
     */
    uint8_t get_dcc_28();

    /** Set the speed from DCC 28 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  @param value bit 7..6:  fixed at b'01'
     *               bit 5:  direction
     *               bits 4:  speed step least significant bit
     *               bits 3..0:  speed step significatn bits 4..1
     */
    void set_dcc_28(uint8_t value);

    /** Get the speed in DCC 14 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  bit 7..6:  fixed at b'01'
     *  bit 5:  direction
     *  bits 4:  reserved 0 for headlight
     *  bits 3..0:  0 = stopped, 4 - 31 = speed steps 1 - 28
     *  @return DCC encoded speed steps
     */
    uint8_t get_dcc_14();

    /** Set the speed from DCC 14 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  @param value bit 7..6:  fixed at b'01'
     *               bit 5:  direction
     *               bits 4:  reserved 0 for headlight
     *               bits 3..0:  0 = stopped, 4 - 31 = speed steps 1 - 28
     */
    void set_dcc_14(uint8_t value);

    /** Get a wire version of the velocity.
     * @return IEEE half precision floating point representation of velocity
     */
    float16_t get_wire()
    {
        float16_t result;
        singles2halfp(&result, &velocity, 1);
        return result;
    }

    /** Set the value based on the wire version of velocity.
     * @param value IEEE half precision floating point representation of velocity
     */
    void set_wire(float16_t value)
    {
        halfp2singles(&velocity, &value, 1);
    }

    /** Overloaded addition operator. */
    Velocity operator + (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity + v.velocity,velocity));
    }

    /** Overloaded addition operator. */
    Velocity operator + (const float& v)
    {
        return Velocity(zero_adjust(velocity + v,velocity));
    }

    /** Overloaded subtraction operator. */
    Velocity operator - (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity - v.velocity,velocity));
    }

    /** Overloaded subtraction operator. */
    Velocity operator - (const float& v)
    {
        return Velocity(zero_adjust(velocity - v,velocity));
    }

    /** Overloaded multiplication operator. */
    Velocity operator * (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity * v.velocity,velocity));
    }

    /** Overloaded multiplication operator. */
    Velocity operator * (const float& v)
    {
        return Velocity(zero_adjust(velocity * v,velocity));
    }

    /** Overloaded division operator. */
    Velocity operator / (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity / v.velocity,velocity));
    }

    /** Overloaded division operator. */
    Velocity operator / (const float& v)
    {
        return Velocity(zero_adjust(velocity / v,velocity));
    }

    /** Overloaded pre-increement operator. */
    Velocity& operator ++ ()
    {
        velocity = zero_adjust(velocity + 1,velocity);
        return *this;
    }

    /** Overloaded post-increment operator. */
    Velocity operator ++ (int)
    {
        Velocity result(*this);
        velocity = zero_adjust(velocity + 1,velocity);
        return result;
    }

    /** Overloaded pre-decreement operator. */
    Velocity& operator -- ()
    {
        velocity = zero_adjust(velocity - 1,velocity);
        return *this;
    }

    /** Overloaded post-decrement operator. */
    Velocity operator -- (int)
    {
        Velocity result(*this);
        velocity = zero_adjust(velocity - 1,velocity);
        return result;
    }

    /** Overloaded addition equals operator. */
    Velocity& operator += (const Velocity& v)
    {
        velocity = zero_adjust(velocity + v.velocity,velocity);
        return *this;
    }

    /** Overloaded addition equals operator. */
    Velocity& operator += (const float& v)
    {
        velocity = zero_adjust(velocity + v,velocity);
        return *this;
    }

    /** Overloaded subtraction equals operator. */
    Velocity& operator -= (const Velocity& v)
    {
        velocity = zero_adjust(velocity - v.velocity,velocity);
        return *this;
    }

    /** Overloaded subtraction equals operator. */
    Velocity& operator -= (const float& v)
    {
        velocity = zero_adjust(velocity - v,velocity);
        return *this;
    }

    /** Overloaded multiplication equals operator. */
    Velocity& operator *= (const Velocity& v)
    {
        velocity = zero_adjust(velocity * v.velocity,velocity);
        return *this;
    }

    /** Overloaded multiplication equals operator. */
    Velocity& operator *= (const float& v)
    {
        velocity = zero_adjust(velocity * v,velocity);
        return *this;
    }

    /** Overloaded division equals operator. */
    Velocity& operator /= (const Velocity& v)
    {
        velocity = zero_adjust(velocity / v.velocity,velocity);
        return *this;
    }

    /** Overloaded division equals operator. */
    Velocity& operator /= (const float& v)
    {
        velocity = zero_adjust(velocity / v,velocity);
        return *this;
    }

    /** Overloaded equals operator. */
    Velocity& operator = (const Velocity& v)
    {
        velocity = v.velocity;
        return *this;
    }

    /** Overloaded equals operator. */
    Velocity& operator = (const float& v)
    {
        velocity = v;
        return *this;
    }

    /** Overloaded equals equals operator */
    bool operator == (const Velocity& v)
    {
        return (v.velocity == velocity);
    }

    /** Overloaded equals equals operator */
    bool operator == (const float& v)
    {
        return (v == velocity);
    }

    /** Overloaded not equals operator */
    bool operator != (const Velocity& v)
    {
        return (v.velocity != velocity);
    }

    /** Overloaded not equals operator */
    bool operator != (const float& v)
    {
        return (v != velocity);
    }

private:
    /** Floating point representation of velocity. */
    float velocity;

    /** Adjust for a math result of negative 0.
     * @param value value of math result
     * @param old original value before expression
     */
    float zero_adjust(float value, float old)
    {
        if (value == 0)
        {
            return copysign(value, old);
        }
        return value;
    }
};

}; /* namespace NMRAnet */

#endif /* _NMRAnetVelocity_hxx_ */
<commit_msg>Fixes m/s to mph conversion in Velocity.<commit_after>/** \copyright
 * Copyright (c) 2013, Stuart W Baker
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
 *
 * \file NMRAnetVelocity.hxx
 * This file provides an implementation of velocity in NMRAnet terms.
 *
 * @author Stuart W. Baker
 * @date 2 August 2013
 */

#ifndef _NMRAnetVelocity_hxx_
#define _NMRAnetVelocity_hxx_

#include <cmath>
#include <cstdint>

#include "utils/macros.h"

extern "C" {
/* These come from the ieeehalfprecision.c */
int singles2halfp(void *target, void *source, int numel);
int halfp2singles(void *target, void *source, int numel);
}

/** Conversion factor for MPH. 1 mph = this many m/s. */
#define MPH_FACTOR 0.44704f

/** This type represents how velocity is seen on the wire (16 bit float).
 */
typedef uint16_t float16_t;

namespace NMRAnet
{

/** This class provides a mechanism for working with velocity in different
 *  forms.  A single precision floating point value is used internally to store
 *  velocity, but this class provides the ability to easily work with
 *  different velocity formats including DCC 14/28/128 speed step formats.
 *  NMRAnet velocity is represented as a floating point meters/sec.  The sign
 *  represents direction where negative is reverse and positive is forward.
 *  Sign is always preserved even when the result is 0.  For example,
 *  -7.0 + 7.0 = -0.0 and 7.0 - 7.0 = +0.0  Be careful thought, per the C
 *  standards, a negative zero (-.0.0) velocity compared to constant 0.0 will
 *  compare true.  Always use @ref direction() when trying to determine the
 *  sign or direction of travel.
 */
class Velocity
{
public:
    /** define an enumeration for direction
     */
    enum
    {
        FORWARD  = 0, /**< forward direction */
        POSITIVE = 0, /**< forward direction */
        REVERSE  = 1, /**< reverse direction */
        NEGATIVE = 1, /**< reverse direction */
    };

    /** Default constructor.
     */
    Velocity()
        : velocity(0)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(int value)
        : velocity(value)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(unsigned int value)
        : velocity(value)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(float value)
        : velocity(value)
    {
    }

    /** Basic constructor.
     * @param value starting value for Velocity.
     */
    Velocity(double value)
        : velocity(value)
    {
    }

    /** Constructor that takes the 16 bit wire format
     * @param value starting value for Velocity as IEEE half precision float.
     */
    Velocity(float16_t value)
        : velocity(halfp2singles(&velocity, &value, 1))
    {
    }

    /** Copy constructor. */
    Velocity(const Velocity& old_velocity)
        : velocity(old_velocity.velocity)
    {
    }

    /** Destructor does nothing. */
    ~Velocity() {}

    /** Return the speed independent of direction.
     * @return speed absolute value of velocity
     */
    float speed()
    {
        return fabsf(velocity);
    }

    /** Return the direction independent of speed.
     * @return direction FORWARD or REVERSE
     */
    int direction()
    {
        if (std::signbit(velocity))
        {
            return REVERSE;
        }
        return FORWARD;
    }

    void set_direction(int direction)
    {
        switch (direction)
        {
        case FORWARD:
            forward();
            break;
        case REVERSE:
            reverse();
            break;
        default:
            DIE("Unexpected direction value");
        }
    }

    /** Set the direction to forward. */
    void forward()
    {
        if (std::signbit(velocity))
        {
            velocity = -velocity;
        }
    }

    /** Set the direction to reverse. */
    void reverse()
    {
        if (!std::signbit(velocity))
        {
            velocity = -velocity;
        }
    }

    /** Convert the native meters/sec representation into mile per hour.
     * @return velocity represented as miles per hour
     */
    float mph()
    {
        return zero_adjust(velocity / MPH_FACTOR, velocity);
    }

    /** Sets the speed value from a given mph value. The sign of the mph value
     * is ignored. */
    void set_mph(float mph)
    {
        velocity = std::copysign(mph * MPH_FACTOR, velocity);
    }

    /** Get the speed in DCC 128 speed step format.
     *  The mapping from meters/sec is strait forward.  First convert to
     *  miles/hour, then each speed step represents 1 mile/hour.  Saturate at
     *  126 miles/hour.
     *
     *  bit 7:  direction
     *  bits 6..0:  0 = stopped, 1 = estop, 2 - 127 = speed steps 1 - 126
     *  @return DCC encoded speed steps
     */
    uint8_t get_dcc_128();

    /** Set the speed from DCC 128 speed step format.
     *  The mapping from meters/sec is strait forward.  First convert to
     *  miles/hour, then each speed step represents 1 mile/hour.  Saturate at
     *  126 miles/hour.
     *
     *  @param value bit 7:  direction
     *               bits 6..0:  0 = stopped, 1 = estop, 2 - 127 = speed steps 1 - 126
     */
    void set_dcc_128(uint8_t value);

    /** Get the speed in DCC 28 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  bit 7..6:  fixed at b'01'
     *  bit 5:  direction
     *  bits 4:  speed step least significant bit
     *  bits 3..0:  speed step significatn bits 4..1
     *  @return DCC encoded speed steps
     */
    uint8_t get_dcc_28();

    /** Set the speed from DCC 28 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  @param value bit 7..6:  fixed at b'01'
     *               bit 5:  direction
     *               bits 4:  speed step least significant bit
     *               bits 3..0:  speed step significatn bits 4..1
     */
    void set_dcc_28(uint8_t value);

    /** Get the speed in DCC 14 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  bit 7..6:  fixed at b'01'
     *  bit 5:  direction
     *  bits 4:  reserved 0 for headlight
     *  bits 3..0:  0 = stopped, 4 - 31 = speed steps 1 - 28
     *  @return DCC encoded speed steps
     */
    uint8_t get_dcc_14();

    /** Set the speed from DCC 14 speed step format.
     *  This is a decimation of the 128 speed step mode.
     *
     *  @param value bit 7..6:  fixed at b'01'
     *               bit 5:  direction
     *               bits 4:  reserved 0 for headlight
     *               bits 3..0:  0 = stopped, 4 - 31 = speed steps 1 - 28
     */
    void set_dcc_14(uint8_t value);

    /** Get a wire version of the velocity.
     * @return IEEE half precision floating point representation of velocity
     */
    float16_t get_wire()
    {
        float16_t result;
        singles2halfp(&result, &velocity, 1);
        return result;
    }

    /** Set the value based on the wire version of velocity.
     * @param value IEEE half precision floating point representation of velocity
     */
    void set_wire(float16_t value)
    {
        halfp2singles(&velocity, &value, 1);
    }

    /** Overloaded addition operator. */
    Velocity operator + (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity + v.velocity,velocity));
    }

    /** Overloaded addition operator. */
    Velocity operator + (const float& v)
    {
        return Velocity(zero_adjust(velocity + v,velocity));
    }

    /** Overloaded subtraction operator. */
    Velocity operator - (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity - v.velocity,velocity));
    }

    /** Overloaded subtraction operator. */
    Velocity operator - (const float& v)
    {
        return Velocity(zero_adjust(velocity - v,velocity));
    }

    /** Overloaded multiplication operator. */
    Velocity operator * (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity * v.velocity,velocity));
    }

    /** Overloaded multiplication operator. */
    Velocity operator * (const float& v)
    {
        return Velocity(zero_adjust(velocity * v,velocity));
    }

    /** Overloaded division operator. */
    Velocity operator / (const Velocity& v)
    {
        return Velocity(zero_adjust(velocity / v.velocity,velocity));
    }

    /** Overloaded division operator. */
    Velocity operator / (const float& v)
    {
        return Velocity(zero_adjust(velocity / v,velocity));
    }

    /** Overloaded pre-increement operator. */
    Velocity& operator ++ ()
    {
        velocity = zero_adjust(velocity + 1,velocity);
        return *this;
    }

    /** Overloaded post-increment operator. */
    Velocity operator ++ (int)
    {
        Velocity result(*this);
        velocity = zero_adjust(velocity + 1,velocity);
        return result;
    }

    /** Overloaded pre-decreement operator. */
    Velocity& operator -- ()
    {
        velocity = zero_adjust(velocity - 1,velocity);
        return *this;
    }

    /** Overloaded post-decrement operator. */
    Velocity operator -- (int)
    {
        Velocity result(*this);
        velocity = zero_adjust(velocity - 1,velocity);
        return result;
    }

    /** Overloaded addition equals operator. */
    Velocity& operator += (const Velocity& v)
    {
        velocity = zero_adjust(velocity + v.velocity,velocity);
        return *this;
    }

    /** Overloaded addition equals operator. */
    Velocity& operator += (const float& v)
    {
        velocity = zero_adjust(velocity + v,velocity);
        return *this;
    }

    /** Overloaded subtraction equals operator. */
    Velocity& operator -= (const Velocity& v)
    {
        velocity = zero_adjust(velocity - v.velocity,velocity);
        return *this;
    }

    /** Overloaded subtraction equals operator. */
    Velocity& operator -= (const float& v)
    {
        velocity = zero_adjust(velocity - v,velocity);
        return *this;
    }

    /** Overloaded multiplication equals operator. */
    Velocity& operator *= (const Velocity& v)
    {
        velocity = zero_adjust(velocity * v.velocity,velocity);
        return *this;
    }

    /** Overloaded multiplication equals operator. */
    Velocity& operator *= (const float& v)
    {
        velocity = zero_adjust(velocity * v,velocity);
        return *this;
    }

    /** Overloaded division equals operator. */
    Velocity& operator /= (const Velocity& v)
    {
        velocity = zero_adjust(velocity / v.velocity,velocity);
        return *this;
    }

    /** Overloaded division equals operator. */
    Velocity& operator /= (const float& v)
    {
        velocity = zero_adjust(velocity / v,velocity);
        return *this;
    }

    /** Overloaded equals operator. */
    Velocity& operator = (const Velocity& v)
    {
        velocity = v.velocity;
        return *this;
    }

    /** Overloaded equals operator. */
    Velocity& operator = (const float& v)
    {
        velocity = v;
        return *this;
    }

    /** Overloaded equals equals operator */
    bool operator == (const Velocity& v)
    {
        return (v.velocity == velocity);
    }

    /** Overloaded equals equals operator */
    bool operator == (const float& v)
    {
        return (v == velocity);
    }

    /** Overloaded not equals operator */
    bool operator != (const Velocity& v)
    {
        return (v.velocity != velocity);
    }

    /** Overloaded not equals operator */
    bool operator != (const float& v)
    {
        return (v != velocity);
    }

private:
    /** Floating point representation of velocity. */
    float velocity;

    /** Adjust for a math result of negative 0.
     * @param value value of math result
     * @param old original value before expression
     */
    float zero_adjust(float value, float old)
    {
        if (value == 0)
        {
            return copysign(value, old);
        }
        return value;
    }
};

}; /* namespace NMRAnet */

#endif /* _NMRAnetVelocity_hxx_ */
<|endoftext|>


<commit_before>#include "SampSharp.h"

#include <mono/metadata/threads.h>
#include "PathUtil.h"
#include "Natives.h"

using namespace std;

MonoMethod *SampSharp::onTimerTick;
MonoMethod *SampSharp::onTick;

MonoDomain *SampSharp::rootDomain;

MonoImage *SampSharp::gameModeImage;
MonoImage *SampSharp::baseModeImage;

MonoClass *SampSharp::gameModeClassType;
MonoClass *SampSharp::baseModeClassType;

uint32_t SampSharp::gameModeHandle;

EventMap SampSharp::events;

void SampSharp::Load(string baseModePath, string gameModePath, string gameModeNamespace, string gameModeClass, bool debug) {

	#ifdef _WIN32
	//On windows, use the embedded mono tools
	mono_set_dirs(PathUtil::GetLibDirectory().c_str(), PathUtil::GetConfigDirectory().c_str());
	#endif

	mono_debug_init(MONO_DEBUG_FORMAT_MONO);

	//Initialize mono runtime
	rootDomain = mono_jit_init(PathUtil::GetPathInBin(gameModePath).c_str());

	//Generate symbols if needed
	#ifdef _WIN32
	if (debug == true) {
		GenerateSymbols(baseModePath);
		GenerateSymbols(gameModePath);
	}
	#endif

	//Load the gamemode's assembly
	gameModeImage = mono_assembly_get_image(mono_domain_assembly_open(mono_domain_get(), (char *)PathUtil::GetPathInBin(gameModePath).c_str()));
	baseModeImage = mono_assembly_get_image(mono_domain_assembly_open(mono_domain_get(), (char *)PathUtil::GetPathInBin(baseModePath).c_str()));

	//Load all sa-mp natives
	LoadNatives();

	//Create instance of the gamemode's class
	baseModeClassType = mono_class_from_name(baseModeImage, "SampSharp.GameMode", "BaseMode");
	gameModeClassType = mono_class_from_name(gameModeImage, gameModeNamespace.c_str(), gameModeClass.c_str());

	MonoObject *gameModeObject = mono_object_new(mono_domain_get(), gameModeClassType);
	gameModeHandle = mono_gchandle_new(gameModeObject, true);
	mono_runtime_object_init(gameModeObject);

	//Load tick events
	onTimerTick = LoadEvent(gameModeClass.c_str(), "OnTimerTick");
	onTick = LoadEvent(gameModeClass.c_str(), "OnTick");
}

#ifdef _WIN32
void SampSharp::GenerateSymbols(string path)
{

	string mdbpath = PathUtil::GetLibDirectory().append("mono/4.5/pdb2mdb.exe");
	char *cmdbpath = new char[mdbpath.size() + 1];
	strcpy(cmdbpath, mdbpath.c_str());

	MonoAssembly *mdbconverter = mono_domain_assembly_open(rootDomain, cmdbpath);
	if (mdbconverter) {
		char *argv[2];
		argv[0] = cmdbpath;
		argv[1] = (char *) path.c_str();

		sampgdk::logprintf("[SampSharp] Generating symbol file for %s.", argv[1]);
		mono_jit_exec(rootDomain, mdbconverter, 2, argv);
	}

	delete cmdbpath;
}
#endif

char *GetTimeStamp() {
	//Get current time
	time_t now = time(0);

	//Format timestamp
	char timestamp[32];

	strftime(timestamp, sizeof(timestamp), "[%d/%m/%Y %H:%M:%S]", localtime(&now));

	char *timestamp2 = new char[32];
	strcpy(timestamp2, timestamp);
	return  timestamp2;
}

MonoMethod *SampSharp::LoadEvent(const char *className, const char *name) {
	char *gamemodeBuffer = new char[128];
	char *basemodeBuffer = new char[128];
	sprintf(gamemodeBuffer, "%s:%s", className, name);
	sprintf(basemodeBuffer, "BaseMode:%s", name);

	MonoMethodDesc *methodDescription = mono_method_desc_new(gamemodeBuffer, false);
	MonoMethod *method = mono_method_desc_search_in_image(methodDescription, gameModeImage);
	mono_method_desc_free(methodDescription);

	if (!method) {
		methodDescription = mono_method_desc_new(basemodeBuffer, false);
		method = mono_method_desc_search_in_image(methodDescription, baseModeImage);
		mono_method_desc_free(methodDescription);

		if (!method) {
			ofstream logfile;
			logfile.open("SampSharp_errors.log", ios::app);
			cout << "[SampSharp] ERROR: Method '" << name << "' not found in image!" << endl;
			logfile << GetTimeStamp() << "ERROR: Method '" << name << "' not found in image!" << endl;
			logfile.close();
		}
	}

	return method;
}

bool SampSharp::HandleEvent(AMX *amx, const char *name, cell *params, cell *retval) {
	const int param_count = params[0] / sizeof(cell);

	if (param_count > 16) {
		return true;
	}

	mono_thread_attach(SampSharp::rootDomain);

	if (events.find(name) == events.end())
	{
		MonoMethod *m_method = mono_class_get_method_from_name(gameModeClassType, name, param_count);
		bool useBaseModeImage = false;
		if (!m_method) {
			m_method = mono_class_get_method_from_name(baseModeClassType, name, param_count);
			useBaseModeImage = true;
		}

		if (!m_method){
			events[name] = NULL;
			return true;
		}

		uint32_t token = mono_method_get_token(m_method);
		MonoMethodSignature *sig = mono_method_get_signature(m_method, useBaseModeImage ? baseModeImage : gameModeImage, token);

		void *iter = NULL;
		string format = "";
		MonoType* type = NULL;

		while (type = mono_signature_get_params(sig, &iter)) {
			string type_name = mono_type_get_name(type);

			if (!type_name.compare("System.Int32")) {
				format.append("i");
			}
			else if (!type_name.compare("System.Single")) {
				format.append("f");
			}
			else if (!type_name.compare("System.String")) {
				format.append("s");
			}
			else if (!type_name.compare("System.Boolean")) {
				format.append("b");
			}
			else {
				events[name] = NULL;
				return true;
			}
		}

		event_t *event_add = new event_t;
		event_add->method = m_method;
		event_add->format = format;
		events[name] = event_add;
	}

	event_t *event_p = events[name];

	if (event_p)
	{
		if (!param_count) {
			int retint = SampSharp::CallEvent(event_p->method, NULL);
			if (retint != -1) {
				*retval = retint;
			}
			return false;
		}
		else {
			void *args[16];
			for (int i = 0; i < param_count; i++) {
				switch (event_p->format[i])
				{
				case 'i':
				case 'f':
				case 'b':
					args[i] = &params[i + 1];
					break;
				case 's':
					int len = NULL;
					cell *addr = NULL;

					amx_GetAddr(amx, params[i + 1], &addr);
					amx_StrLen(addr, &len);

					if (len) {
						len++;

						char* text = new char[len];

						amx_GetString(text, addr, 0, len);
						args[i] = mono_string_new(mono_domain_get(), text);
					}
					else {
						args[i] = mono_string_new(mono_domain_get(), "");
					}
					break;
				}
			}

			int retint = SampSharp::CallEvent(event_p->method, args);

			if (retint != -1) {
				*retval = retint;
			}
			return false;
		}
		return false;
	}

	return true;
}

int SampSharp::CallEvent(MonoMethod* method, void **params) {

	MonoObject *exception = NULL;

	if (!method) {
		ofstream logfile;
		logfile.open("SampSharp_errors.log", ios::app);
		cout << "[SampSharp] ERROR: No method given in CallEvent!" << endl;
		logfile << GetTimeStamp() << "ERROR: No method given in CallEvent!" << endl;
		logfile.close();

		return false;
	}

	MonoObject *response = mono_runtime_invoke(method, mono_gchandle_get_target(gameModeHandle), params, &exception);

	if (exception) {
		char *stacktrace = mono_string_to_utf8(mono_object_to_string(exception, NULL));

		ofstream logfile;
		logfile.open("SampSharp_errors.log", ios::app | ios::binary);
		cout << "[SampSharp] Exception thrown:" << endl << stacktrace << endl;
		logfile << GetTimeStamp() << " Exception thrown:" << "\r\n" << stacktrace << "\r\n";
		logfile.close();

		return -1;
	}

	if (!response) {
		return -1;
	}

	return *(bool *)mono_object_unbox(response) == true ? 1 : 0;;
}

void SampSharp::Unload() {
	mono_jit_cleanup(mono_domain_get());
}
<commit_msg>Fixed crash on incompatible callbacks<commit_after>#include "SampSharp.h"

#include <mono/metadata/threads.h>
#include "PathUtil.h"
#include "Natives.h"

using namespace std;

MonoMethod *SampSharp::onTimerTick;
MonoMethod *SampSharp::onTick;

MonoDomain *SampSharp::rootDomain;

MonoImage *SampSharp::gameModeImage;
MonoImage *SampSharp::baseModeImage;

MonoClass *SampSharp::gameModeClassType;
MonoClass *SampSharp::baseModeClassType;

uint32_t SampSharp::gameModeHandle;

EventMap SampSharp::events;

void SampSharp::Load(string baseModePath, string gameModePath, string gameModeNamespace, string gameModeClass, bool debug) {

	#ifdef _WIN32
	//On windows, use the embedded mono tools
	mono_set_dirs(PathUtil::GetLibDirectory().c_str(), PathUtil::GetConfigDirectory().c_str());
	#endif

	mono_debug_init(MONO_DEBUG_FORMAT_MONO);

	//Initialize mono runtime
	rootDomain = mono_jit_init(PathUtil::GetPathInBin(gameModePath).c_str());

	//Generate symbols if needed
	#ifdef _WIN32
	if (debug == true) {
		GenerateSymbols(baseModePath);
		GenerateSymbols(gameModePath);
	}
	#endif

	//Load the gamemode's assembly
	gameModeImage = mono_assembly_get_image(mono_domain_assembly_open(mono_domain_get(), (char *)PathUtil::GetPathInBin(gameModePath).c_str()));
	baseModeImage = mono_assembly_get_image(mono_domain_assembly_open(mono_domain_get(), (char *)PathUtil::GetPathInBin(baseModePath).c_str()));

	//Load all sa-mp natives
	LoadNatives();

	//Create instance of the gamemode's class
	baseModeClassType = mono_class_from_name(baseModeImage, "SampSharp.GameMode", "BaseMode");
	gameModeClassType = mono_class_from_name(gameModeImage, gameModeNamespace.c_str(), gameModeClass.c_str());

	MonoObject *gameModeObject = mono_object_new(mono_domain_get(), gameModeClassType);
	gameModeHandle = mono_gchandle_new(gameModeObject, true);
	mono_runtime_object_init(gameModeObject);

	//Load tick events
	onTimerTick = LoadEvent(gameModeClass.c_str(), "OnTimerTick");
	onTick = LoadEvent(gameModeClass.c_str(), "OnTick");
}

#ifdef _WIN32
void SampSharp::GenerateSymbols(string path)
{

	string mdbpath = PathUtil::GetLibDirectory().append("mono/4.5/pdb2mdb.exe");
	char *cmdbpath = new char[mdbpath.size() + 1];
	strcpy(cmdbpath, mdbpath.c_str());

	MonoAssembly *mdbconverter = mono_domain_assembly_open(rootDomain, cmdbpath);
	if (mdbconverter) {
		char *argv[2];
		argv[0] = cmdbpath;
		argv[1] = (char *) path.c_str();

		sampgdk::logprintf("[SampSharp] Generating symbol file for %s.", argv[1]);
		mono_jit_exec(rootDomain, mdbconverter, 2, argv);
	}

	delete cmdbpath;
}
#endif

char *GetTimeStamp() {
	//Get current time
	time_t now = time(0);

	//Format timestamp
	char timestamp[32];

	strftime(timestamp, sizeof(timestamp), "[%d/%m/%Y %H:%M:%S]", localtime(&now));

	char *timestamp2 = new char[32];
	strcpy(timestamp2, timestamp);
	return  timestamp2;
}

MonoMethod *SampSharp::LoadEvent(const char *className, const char *name) {
	char *gamemodeBuffer = new char[128];
	char *basemodeBuffer = new char[128];
	sprintf(gamemodeBuffer, "%s:%s", className, name);
	sprintf(basemodeBuffer, "BaseMode:%s", name);

	MonoMethodDesc *methodDescription = mono_method_desc_new(gamemodeBuffer, false);
	MonoMethod *method = mono_method_desc_search_in_image(methodDescription, gameModeImage);
	mono_method_desc_free(methodDescription);

	if (!method) {
		methodDescription = mono_method_desc_new(basemodeBuffer, false);
		method = mono_method_desc_search_in_image(methodDescription, baseModeImage);
		mono_method_desc_free(methodDescription);

		if (!method) {
			ofstream logfile;
			logfile.open("SampSharp_errors.log", ios::app);
			cout << "[SampSharp] ERROR: Method '" << name << "' not found in image!" << endl;
			logfile << GetTimeStamp() << "ERROR: Method '" << name << "' not found in image!" << endl;
			logfile.close();
		}
	}

	return method;
}

bool SampSharp::HandleEvent(AMX *amx, const char *name, cell *params, cell *retval) {
	const int param_count = params[0] / sizeof(cell);

	if (strlen(name) == 0 || param_count > 16) {
		return true;
	}

	mono_thread_attach(SampSharp::rootDomain);

	if (events.find(name) == events.end())
	{
		MonoMethod *m_method = mono_class_get_method_from_name(gameModeClassType, name, param_count);
		bool useBaseModeImage = false;
		if (!m_method) {
			m_method = mono_class_get_method_from_name(baseModeClassType, name, param_count);
			useBaseModeImage = true;
		}

		if (!m_method){
			events[name] = NULL;
			return true;
		}

		uint32_t token = mono_method_get_token(m_method);
		MonoMethodSignature *sig = mono_method_get_signature(m_method, useBaseModeImage ? baseModeImage : gameModeImage, token);

		void *iter = NULL;
		string format = "";
		MonoType* type = NULL;

		while (type = mono_signature_get_params(sig, &iter)) {
			string type_name = mono_type_get_name(type);

			if (!type_name.compare("System.Int32")) {
				format.append("i");
			}
			else if (!type_name.compare("System.Single")) {
				format.append("f");
			}
			else if (!type_name.compare("System.String")) {
				format.append("s");
			}
			else if (!type_name.compare("System.Boolean")) {
				format.append("b");
			}
			else {
				events[name] = NULL;
				return true;
			}
		}

		event_t *event_add = new event_t;
		event_add->method = m_method;
		event_add->format = format;
		events[name] = event_add;
	}

	event_t *event_p = events[name];

	if (event_p)
	{
		if (!param_count) {
			int retint = SampSharp::CallEvent(event_p->method, NULL);
			if (retint != -1) {
				*retval = retint;
			}
			return false;
		}
		else {
			void *args[16];
			for (int i = 0; i < param_count; i++) {
				switch (event_p->format[i])
				{
				case 'i':
				case 'f':
				case 'b':
					args[i] = &params[i + 1];
					break;
				case 's':
					int len = NULL;
					cell *addr = NULL;

					amx_GetAddr(amx, params[i + 1], &addr);
					amx_StrLen(addr, &len);

					if (len) {
						len++;

						char* text = new char[len];

						amx_GetString(text, addr, 0, len);
						args[i] = mono_string_new(mono_domain_get(), text);
					}
					else {
						args[i] = mono_string_new(mono_domain_get(), "");
					}
					break;
				}
			}

			int retint = SampSharp::CallEvent(event_p->method, args);

			if (retint != -1) {
				*retval = retint;
			}
			return false;
		}
		return false;
	}

	return true;
}

int SampSharp::CallEvent(MonoMethod* method, void **params) {

	MonoObject *exception = NULL;

	if (!method) {
		ofstream logfile;
		logfile.open("SampSharp_errors.log", ios::app);
		cout << "[SampSharp] ERROR: No method given in CallEvent!" << endl;
		logfile << GetTimeStamp() << "ERROR: No method given in CallEvent!" << endl;
		logfile.close();

		return false;
	}

	MonoObject *response = mono_runtime_invoke(method, mono_gchandle_get_target(gameModeHandle), params, &exception);

	if (exception) {
		char *stacktrace = mono_string_to_utf8(mono_object_to_string(exception, NULL));

		ofstream logfile;
		logfile.open("SampSharp_errors.log", ios::app | ios::binary);
		cout << "[SampSharp] Exception thrown:" << endl << stacktrace << endl;
		logfile << GetTimeStamp() << " Exception thrown:" << "\r\n" << stacktrace << "\r\n";
		logfile.close();

		return -1;
	}

	if (!response) {
		return -1;
	}

	return *(bool *)mono_object_unbox(response) == true ? 1 : 0;;
}

void SampSharp::Unload() {
	mono_jit_cleanup(mono_domain_get());
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling -I%p -Xclang -verify 2>&1 | FileCheck %s

// Test the removal of decls which are stored in vector of redeclarables
.rawInput 1
extern int __my_i;
template<typename T> T TemplatedF(T t);
template<> double TemplatedF(double); // forward declare TemplatedF
int OverloadedF(int i);
float OverloadedF(float f){ return f + 100.111f;}
double OverloadedF(double d){ return d + 10.11f; };
namespace test { int y = 0; }
.rawInput 0

.storeState "testSubsequentDecls"
#include "SubsequentDecls.h"
.compareState "testSubsequentDecls"
// CHECK-NOT: Differences

TemplatedF((int)2) // expected-diagnostics{{C++ requires a type specifier for all declarations}} expected-diagnostics{{expected ';' after top level declarator}}

.rawInput 1
template<> int TemplatedF(int i) { return i + 100; }
int OverloadedF(int i) { return i + 100;}
.rawInput 0

int __my_i = 10
// CHECK: (int) 10
OverloadedF(__my_i)
// CHECK: (int) 110
TemplatedF(__my_i)
// CHECK: (int) 110

TemplatedF((double)3.14)
// CHECK: IncrementalExecutor::executeFunction: symbol '_Z10TemplatedFIdET_S0_' unresolved while linking function

.q
<commit_msg>Error now comes during reloc (static init).<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling -I%p -Xclang -verify 2>&1 | FileCheck %s

// Test the removal of decls which are stored in vector of redeclarables
.rawInput 1
extern int __my_i;
template<typename T> T TemplatedF(T t);
template<> double TemplatedF(double); // forward declare TemplatedF
int OverloadedF(int i);
float OverloadedF(float f){ return f + 100.111f;}
double OverloadedF(double d){ return d + 10.11f; };
namespace test { int y = 0; }
.rawInput 0

.storeState "testSubsequentDecls"
#include "SubsequentDecls.h"
.compareState "testSubsequentDecls"
// CHECK-NOT: Differences

TemplatedF((int)2) // expected-diagnostics{{C++ requires a type specifier for all declarations}} expected-diagnostics{{expected ';' after top level declarator}}

.rawInput 1
template<> int TemplatedF(int i) { return i + 100; }
int OverloadedF(int i) { return i + 100;}
.rawInput 0

int __my_i = 10
// CHECK: (int) 10
OverloadedF(__my_i)
// CHECK: (int) 110
TemplatedF(__my_i)
// CHECK: (int) 110

TemplatedF((double)3.14)
// CHECK: IncrementalExecutor::executeFunction: symbol '_Z10TemplatedFIdET_S0_' unresolved while linking

.q
<|endoftext|>