<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 author 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <algorithm>

#include "libtorrent/config.hpp"
#include "libtorrent/gzip.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/bind.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/http_connection.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/io.hpp"

using namespace libtorrent;
using boost::bind;

namespace libtorrent
{

	http_tracker_connection::http_tracker_connection(
		io_service& ios
		, connection_queue& cc
		, tracker_manager& man
		, tracker_request const& req
		, address bind_infc
		, boost::weak_ptr<request_callback> c
		, session_settings const& stn
		, proxy_settings const& ps
		, std::string const& auth)
		: tracker_connection(man, req, ios, bind_infc, c)
		, m_man(man)
	{
		// TODO: authentication
		std::string url = req.url;

		if (req.kind == tracker_request::scrape_request)
		{
			// find and replace "announce" with "scrape"
			// in request

			std::size_t pos = url.find("announce");
			if (pos == std::string::npos)
			{
				fail(-1, ("scrape is not available on url: '"
					+ req.url +"'").c_str());
				return;
			}
			url.replace(pos, 8, "scrape");
		}

		// if request-string already contains
		// some parameters, append an ampersand instead
		// of a question mark
		size_t arguments_start = url.find('?');
		if (arguments_start != std::string::npos)
			url += "&";
		else
			url += "?";

		url += "info_hash=";
		url += escape_string(
			reinterpret_cast<const char*>(req.info_hash.begin()), 20);

		if (req.kind == tracker_request::announce_request)
		{
			url += "&peer_id=";
			url += escape_string(
				reinterpret_cast<const char*>(req.pid.begin()), 20);

			url += "&port=";
			url += boost::lexical_cast<std::string>(req.listen_port);

			url += "&uploaded=";
			url += boost::lexical_cast<std::string>(req.uploaded);

			url += "&downloaded=";
			url += boost::lexical_cast<std::string>(req.downloaded);

			url += "&left=";
			url += boost::lexical_cast<std::string>(req.left);

			if (req.event != tracker_request::none)
			{
				const char* event_string[] = {"completed", "started", "stopped"};
				url += "&event=";
				url += event_string[req.event - 1];
			}

			url += "&key=";
			std::stringstream key_string;
			key_string << std::hex << req.key;
			url += key_string.str();

			url += "&compact=1";

			url += "&numwant=";
			url += boost::lexical_cast<std::string>(
				(std::min)(req.num_want, 999));

			if (stn.announce_ip != address())
			{
				url += "&ip=";
				url += stn.announce_ip.to_string();
			}

#ifndef TORRENT_DISABLE_ENCRYPTION
			url += "&supportcrypto=1";
#endif
			url += "&ipv6=";
			url += req.ipv6;

			// extension that tells the tracker that
			// we don't need any peer_id's in the response
			url += "&no_peer_id=1";
		}

		m_tracker_connection.reset(new http_connection(ios, cc
			, boost::bind(&http_tracker_connection::on_response, self(), _1, _2, _3, _4)));

		m_tracker_connection->get(url, seconds(stn.tracker_completion_timeout)
			, &ps, 5, stn.user_agent, bind_infc);

#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)

		boost::shared_ptr<request_callback> cb = requester();
		if (cb)
		{
			cb->debug_log("==> TRACKER_REQUEST [ url: " + url + " ]");
		}
#endif
	}

	void http_tracker_connection::close()
	{
		if (m_tracker_connection)
		{
			m_tracker_connection->close();
			m_tracker_connection.reset();
		}
		tracker_connection::close();
	}

	void http_tracker_connection::on_response(asio::error_code const& ec
		, http_parser const& parser, char const* data, int size)
	{
		// keep this alive
		boost::intrusive_ptr<http_tracker_connection> me(this);

		if (!parser.header_finished())
		{
			fail(-1, "premature end of file");
			return;
		}

		if (parser.status_code() != 200)
		{
			fail(parser.status_code(), parser.message().c_str());
			return;
		}

		if (ec && ec != asio::error::eof)
		{
			fail(parser.status_code(), ec.message().c_str());
			return;
		}

		// handle tracker response
		entry e = bdecode(data, data + size);

		if (e.type() != entry::undefined_t)
		{
			parse(parser.status_code(), e);
		}
		else
		{
			std::string error_str("invalid bencoding of tracker response: \"");
			for (char const* i = data, *end(data + size); i != end; ++i)
			{
				if (std::isprint(*i)) error_str += *i;
				else error_str += "0x" + boost::lexical_cast<std::string>((unsigned int)*i) + " ";
			}
			error_str += "\"";
			fail(parser.status_code(), error_str.c_str());
		}
		close();
	}

	bool http_tracker_connection::extract_peer_info(const entry& info, peer_entry& ret)
	{
		// extract peer id (if any)
		if (info.type() != entry::dictionary_t)
		{
			fail(-1, "invalid response from tracker (invalid peer entry)");
			return false;
		}
		entry const* i = info.find_key("peer id");
		if (i != 0)
		{
			if (i->type() != entry::string_t || i->string().length() != 20)
			{
				fail(-1, "invalid response from tracker (invalid peer id)");
				return false;
			}
			std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
		}
		else
		{
			// if there's no peer_id, just initialize it to a bunch of zeroes
			std::fill_n(ret.pid.begin(), 20, 0);
		}

		// extract ip
		i = info.find_key("ip");
		if (i == 0 || i->type() != entry::string_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.ip = i->string();

		// extract port
		i = info.find_key("port");
		if (i == 0 || i->type() != entry::int_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.port = (unsigned short)i->integer();

		return true;
	}

	void http_tracker_connection::parse(int status_code, entry const& e)
	{
		boost::shared_ptr<request_callback> cb = requester();
		if (!cb) return;

		// parse the response
		entry const* failure = e.find_key("failure reason");
		if (failure && failure->type() == entry::string_t)
		{
			fail(status_code, failure->string().c_str());
			return;
		}

		entry const* warning = e.find_key("warning message");
		if (warning && warning->type() == entry::string_t)
		{
			cb->tracker_warning(warning->string());
		}

		std::vector<peer_entry> peer_list;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			std::string ih;
			std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
				, std::back_inserter(ih));

			entry const* files = e.find_key("files");
			if (files == 0 || files->type() != entry::dictionary_t)
			{
				fail(-1, "invalid or missing 'files' entry in scrape response");
				return;
			}

			entry const* scrape_data = e.find_key(ih.c_str());
			if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
			{
				fail(-1, "missing or invalid info-hash entry in scrape response");
				return;
			}
			entry const* complete = scrape_data->find_key("complete");
			entry const* incomplete = scrape_data->find_key("incomplete");
			entry const* downloaded = scrape_data->find_key("downloaded");
			if (complete == 0 || incomplete == 0 || downloaded == 0
				|| complete->type() != entry::int_t
				|| incomplete->type() != entry::int_t
				|| downloaded->type() != entry::int_t)
			{
				fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
				return;
			}
			cb->tracker_scrape_response(tracker_req(), complete->integer()
				, incomplete->integer(), downloaded->integer());
			return;
		}

		entry const* interval = e.find_key("interval");
		if (interval == 0 || interval->type() != entry::int_t)
		{
			fail(-1, "missing or invalid 'interval' entry in tracker response");
			return;
		}

		entry const* peers_ent = e.find_key("peers");
		if (peers_ent == 0)
		{
			fail(-1, "missing 'peers' entry in tracker response");
			return;
		}

		if (peers_ent->type() == entry::string_t)
		{
			std::string const& peers = peers_ent->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 6) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v4_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}
		else if (peers_ent->type() == entry::list_t)
		{
			entry::list_type const& l = peers_ent->list();
			for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
			{
				peer_entry p;
				if (!extract_peer_info(*i, p)) return;
				peer_list.push_back(p);
			}
		}
		else
		{
			fail(-1, "invalid 'peers' entry in tracker response");
			return;
		}

		entry const* ipv6_peers = e.find_key("peers6");
		if (ipv6_peers && ipv6_peers->type() == entry::string_t)
		{
			std::string const& peers = ipv6_peers->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 18) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v6_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}

		// look for optional scrape info
		int complete = -1;
		int incomplete = -1;

		entry const* complete_ent = e.find_key("complete");
		if (complete_ent && complete_ent->type() == entry::int_t)
			complete = complete_ent->integer();

		entry const* incomplete_ent = e.find_key("incomplete");
		if (incomplete_ent && incomplete_ent->type() == entry::int_t)
			incomplete = incomplete_ent->integer();

		cb->tracker_response(tracker_req(), peer_list, interval->integer(), complete
			, incomplete);
	}

}

<commit_msg>improved tracker error messages<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 author 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <algorithm>

#include "libtorrent/config.hpp"
#include "libtorrent/gzip.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/bind.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/http_connection.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/io.hpp"

using namespace libtorrent;
using boost::bind;

namespace libtorrent
{

	http_tracker_connection::http_tracker_connection(
		io_service& ios
		, connection_queue& cc
		, tracker_manager& man
		, tracker_request const& req
		, address bind_infc
		, boost::weak_ptr<request_callback> c
		, session_settings const& stn
		, proxy_settings const& ps
		, std::string const& auth)
		: tracker_connection(man, req, ios, bind_infc, c)
		, m_man(man)
	{
		// TODO: authentication
		std::string url = req.url;

		if (req.kind == tracker_request::scrape_request)
		{
			// find and replace "announce" with "scrape"
			// in request

			std::size_t pos = url.find("announce");
			if (pos == std::string::npos)
			{
				fail(-1, ("scrape is not available on url: '"
					+ req.url +"'").c_str());
				return;
			}
			url.replace(pos, 8, "scrape");
		}

		// if request-string already contains
		// some parameters, append an ampersand instead
		// of a question mark
		size_t arguments_start = url.find('?');
		if (arguments_start != std::string::npos)
			url += "&";
		else
			url += "?";

		url += "info_hash=";
		url += escape_string(
			reinterpret_cast<const char*>(req.info_hash.begin()), 20);

		if (req.kind == tracker_request::announce_request)
		{
			url += "&peer_id=";
			url += escape_string(
				reinterpret_cast<const char*>(req.pid.begin()), 20);

			url += "&port=";
			url += boost::lexical_cast<std::string>(req.listen_port);

			url += "&uploaded=";
			url += boost::lexical_cast<std::string>(req.uploaded);

			url += "&downloaded=";
			url += boost::lexical_cast<std::string>(req.downloaded);

			url += "&left=";
			url += boost::lexical_cast<std::string>(req.left);

			if (req.event != tracker_request::none)
			{
				const char* event_string[] = {"completed", "started", "stopped"};
				url += "&event=";
				url += event_string[req.event - 1];
			}

			url += "&key=";
			std::stringstream key_string;
			key_string << std::hex << req.key;
			url += key_string.str();

			url += "&compact=1";

			url += "&numwant=";
			url += boost::lexical_cast<std::string>(
				(std::min)(req.num_want, 999));

			if (stn.announce_ip != address())
			{
				url += "&ip=";
				url += stn.announce_ip.to_string();
			}

#ifndef TORRENT_DISABLE_ENCRYPTION
			url += "&supportcrypto=1";
#endif
			url += "&ipv6=";
			url += req.ipv6;

			// extension that tells the tracker that
			// we don't need any peer_id's in the response
			url += "&no_peer_id=1";
		}

		m_tracker_connection.reset(new http_connection(ios, cc
			, boost::bind(&http_tracker_connection::on_response, self(), _1, _2, _3, _4)));

		m_tracker_connection->get(url, seconds(stn.tracker_completion_timeout)
			, &ps, 5, stn.user_agent, bind_infc);

#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)

		boost::shared_ptr<request_callback> cb = requester();
		if (cb)
		{
			cb->debug_log("==> TRACKER_REQUEST [ url: " + url + " ]");
		}
#endif
	}

	void http_tracker_connection::close()
	{
		if (m_tracker_connection)
		{
			m_tracker_connection->close();
			m_tracker_connection.reset();
		}
		tracker_connection::close();
	}

	void http_tracker_connection::on_response(asio::error_code const& ec
		, http_parser const& parser, char const* data, int size)
	{
		// keep this alive
		boost::intrusive_ptr<http_tracker_connection> me(this);

		if (ec && ec != asio::error::eof)
		{
			fail(-1, ec.message().c_str());
			return;
		}

		if (!parser.header_finished())
		{
			fail(-1, "premature end of file");
			return;
		}

		if (parser.status_code() != 200)
		{
			fail(parser.status_code(), parser.message().c_str());
			return;
		}

		if (ec && ec != asio::error::eof)
		{
			fail(parser.status_code(), ec.message().c_str());
			return;
		}

		// handle tracker response
		entry e = bdecode(data, data + size);

		if (e.type() != entry::undefined_t)
		{
			parse(parser.status_code(), e);
		}
		else
		{
			std::string error_str("invalid bencoding of tracker response: \"");
			for (char const* i = data, *end(data + size); i != end; ++i)
			{
				if (std::isprint(*i)) error_str += *i;
				else error_str += "0x" + boost::lexical_cast<std::string>((unsigned int)*i) + " ";
			}
			error_str += "\"";
			fail(parser.status_code(), error_str.c_str());
		}
		close();
	}

	bool http_tracker_connection::extract_peer_info(const entry& info, peer_entry& ret)
	{
		// extract peer id (if any)
		if (info.type() != entry::dictionary_t)
		{
			fail(-1, "invalid response from tracker (invalid peer entry)");
			return false;
		}
		entry const* i = info.find_key("peer id");
		if (i != 0)
		{
			if (i->type() != entry::string_t || i->string().length() != 20)
			{
				fail(-1, "invalid response from tracker (invalid peer id)");
				return false;
			}
			std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
		}
		else
		{
			// if there's no peer_id, just initialize it to a bunch of zeroes
			std::fill_n(ret.pid.begin(), 20, 0);
		}

		// extract ip
		i = info.find_key("ip");
		if (i == 0 || i->type() != entry::string_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.ip = i->string();

		// extract port
		i = info.find_key("port");
		if (i == 0 || i->type() != entry::int_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.port = (unsigned short)i->integer();

		return true;
	}

	void http_tracker_connection::parse(int status_code, entry const& e)
	{
		boost::shared_ptr<request_callback> cb = requester();
		if (!cb) return;

		// parse the response
		entry const* failure = e.find_key("failure reason");
		if (failure && failure->type() == entry::string_t)
		{
			fail(status_code, failure->string().c_str());
			return;
		}

		entry const* warning = e.find_key("warning message");
		if (warning && warning->type() == entry::string_t)
		{
			cb->tracker_warning(warning->string());
		}

		std::vector<peer_entry> peer_list;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			std::string ih;
			std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
				, std::back_inserter(ih));

			entry const* files = e.find_key("files");
			if (files == 0 || files->type() != entry::dictionary_t)
			{
				fail(-1, "invalid or missing 'files' entry in scrape response");
				return;
			}

			entry const* scrape_data = e.find_key(ih.c_str());
			if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
			{
				fail(-1, "missing or invalid info-hash entry in scrape response");
				return;
			}
			entry const* complete = scrape_data->find_key("complete");
			entry const* incomplete = scrape_data->find_key("incomplete");
			entry const* downloaded = scrape_data->find_key("downloaded");
			if (complete == 0 || incomplete == 0 || downloaded == 0
				|| complete->type() != entry::int_t
				|| incomplete->type() != entry::int_t
				|| downloaded->type() != entry::int_t)
			{
				fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
				return;
			}
			cb->tracker_scrape_response(tracker_req(), complete->integer()
				, incomplete->integer(), downloaded->integer());
			return;
		}

		entry const* interval = e.find_key("interval");
		if (interval == 0 || interval->type() != entry::int_t)
		{
			fail(-1, "missing or invalid 'interval' entry in tracker response");
			return;
		}

		entry const* peers_ent = e.find_key("peers");
		if (peers_ent == 0)
		{
			fail(-1, "missing 'peers' entry in tracker response");
			return;
		}

		if (peers_ent->type() == entry::string_t)
		{
			std::string const& peers = peers_ent->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 6) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v4_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}
		else if (peers_ent->type() == entry::list_t)
		{
			entry::list_type const& l = peers_ent->list();
			for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
			{
				peer_entry p;
				if (!extract_peer_info(*i, p)) return;
				peer_list.push_back(p);
			}
		}
		else
		{
			fail(-1, "invalid 'peers' entry in tracker response");
			return;
		}

		entry const* ipv6_peers = e.find_key("peers6");
		if (ipv6_peers && ipv6_peers->type() == entry::string_t)
		{
			std::string const& peers = ipv6_peers->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 18) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v6_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}

		// look for optional scrape info
		int complete = -1;
		int incomplete = -1;

		entry const* complete_ent = e.find_key("complete");
		if (complete_ent && complete_ent->type() == entry::int_t)
			complete = complete_ent->integer();

		entry const* incomplete_ent = e.find_key("incomplete");
		if (incomplete_ent && incomplete_ent->type() == entry::int_t)
			incomplete = incomplete_ent->integer();

		cb->tracker_response(tracker_req(), peer_list, interval->integer(), complete
			, incomplete);
	}

}

<|endoftext|>


<commit_before>
#include "Ext.h"

#include <llvm/IR/Function.h>
#include <llvm/IR/TypeBuilder.h>
#include <llvm/IR/IntrinsicInst.h>

//#include <libdevcrypto/SHA3.h>
//#include <libevm/FeeStructure.h>

#include "RuntimeManager.h"
#include "Memory.h"
#include "Type.h"
#include "Endianness.h"

namespace dev
{
namespace eth
{
namespace jit
{

Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan):
	RuntimeHelper(_runtimeManager),
	m_memoryMan(_memoryMan)
#ifdef __MSCVER
	,
	m_funcs({}),  // The only std::array initialization that works in both Visual Studio & GCC
	m_argAllocas({})
#endif
{
	m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size");
}

using FuncDesc = std::tuple<char const*, llvm::FunctionType*>;

llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list<llvm::Type*> const& _argsTypes)
{
	return llvm::FunctionType::get(_returnType, llvm::ArrayRef<llvm::Type*>{_argsTypes.begin(), _argsTypes.size()}, false);
}

std::array<FuncDesc, sizeOf<EnvFunc>::value> const& getEnvFuncDescs()
{
	static std::array<FuncDesc, sizeOf<EnvFunc>::value> descs{{
		FuncDesc{"env_sload",   getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_sstore",  getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})},
		FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})},
		FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
		FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})},
		FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})},
	}};

	return descs;
}

llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module)
{
	auto&& desc = getEnvFuncDescs()[static_cast<size_t>(_id)];
	return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module);
}

llvm::Value* Ext::getArgAlloca()
{
	auto& a = m_argAllocas[m_argCounter++];
	if (!a)
	{
		// FIXME: Improve order and names
		InsertPointGuard g{getBuilder()};
		getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI());
		a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg");
	}

	return a;
}

llvm::Value* Ext::byPtr(llvm::Value* _value)
{
	auto a = getArgAlloca();
	getBuilder().CreateStore(_value, a);
	return a;
}

llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list<llvm::Value*> const& _args)
{
	auto& func = m_funcs[static_cast<size_t>(_funcId)];
	if (!func)
		func = createFunc(_funcId, getModule());

	m_argCounter = 0;
	return getBuilder().CreateCall(func, {_args.begin(), _args.size()});
}

llvm::Value* Ext::sload(llvm::Value* _index)
{
	auto ret = getArgAlloca();
	createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness
	return m_builder.CreateLoad(ret);
}

void Ext::sstore(llvm::Value* _index, llvm::Value* _value)
{
	createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness
}

llvm::Value* Ext::calldataload(llvm::Value* _index)
{
	auto ret = getArgAlloca();
	createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret});
	ret = m_builder.CreateLoad(ret);
	return Endianness::toNative(m_builder, ret);
}

llvm::Value* Ext::balance(llvm::Value* _address)
{
	auto address = Endianness::toBE(m_builder, _address);
	auto ret = getArgAlloca();
	createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret});
	return m_builder.CreateLoad(ret);
}

llvm::Value* Ext::blockhash(llvm::Value* _number)
{
	auto hash = getArgAlloca();
	createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash});
	hash =  m_builder.CreateLoad(hash);
	return Endianness::toNative(getBuilder(), hash);
}

llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
{
	auto gas = byPtr(_gas);
	auto ret = getArgAlloca();
	auto begin = m_memoryMan.getBytePtr(_initOff);
	auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
	createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret});
	_gas = m_builder.CreateLoad(gas); // Return gas
	llvm::Value* address = m_builder.CreateLoad(ret);
	address = Endianness::toNative(m_builder, address);
	return address;
}

llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress)
{
	auto gas = byPtr(_gas);
	auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress);
	auto inBeg = m_memoryMan.getBytePtr(_inOff);
	auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size");
	auto outBeg = m_memoryMan.getBytePtr(_outOff);
	auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
	auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
	auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
	_gas = m_builder.CreateLoad(gas); // Return gas
	return m_builder.CreateZExt(ret, Type::Word, "ret");
}

llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
{
	auto begin = m_memoryMan.getBytePtr(_inOff);
	auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size");
	auto ret = getArgAlloca();
	createCall(EnvFunc::sha3, {begin, size, ret});
	llvm::Value* hash = m_builder.CreateLoad(ret);
	hash = Endianness::toNative(m_builder, hash);
	return hash;
}

MemoryRef Ext::extcode(llvm::Value* _addr)
{
	auto addr = Endianness::toBE(m_builder, _addr);
	auto code = createCall(EnvFunc::extcode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size});
	auto codeSize = m_builder.CreateLoad(m_size);
	auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word);
	return {code, codeSize256};
}

void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array<llvm::Value*,4> const& _topics)
{
	auto begin = m_memoryMan.getBytePtr(_memIdx);
	auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size");
	llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, getArgAlloca(), getArgAlloca(), getArgAlloca(), getArgAlloca()};

	auto topicArgPtr = &args[3];
	for (auto&& topic : _topics)
	{
		if (topic)
			m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr);
		else
			*topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr);
		++topicArgPtr;
	}

	createCall(EnvFunc::log, {args[0], args[1], args[2], args[3], args[4], args[5], args[6]});  // TODO: use std::initializer_list<>
}

}
}
}
<commit_msg>Correct std::array intialization (again!)<commit_after>
#include "Ext.h"

#include <llvm/IR/Function.h>
#include <llvm/IR/TypeBuilder.h>
#include <llvm/IR/IntrinsicInst.h>

//#include <libdevcrypto/SHA3.h>
//#include <libevm/FeeStructure.h>

#include "RuntimeManager.h"
#include "Memory.h"
#include "Type.h"
#include "Endianness.h"

namespace dev
{
namespace eth
{
namespace jit
{

Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan):
	RuntimeHelper(_runtimeManager),
	m_memoryMan(_memoryMan)
{
	m_funcs = decltype(m_funcs)();
	m_argAllocas = decltype(m_argAllocas)();
	m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size");
}

using FuncDesc = std::tuple<char const*, llvm::FunctionType*>;

llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list<llvm::Type*> const& _argsTypes)
{
	return llvm::FunctionType::get(_returnType, llvm::ArrayRef<llvm::Type*>{_argsTypes.begin(), _argsTypes.size()}, false);
}

std::array<FuncDesc, sizeOf<EnvFunc>::value> const& getEnvFuncDescs()
{
	static std::array<FuncDesc, sizeOf<EnvFunc>::value> descs{{
		FuncDesc{"env_sload",   getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_sstore",  getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})},
		FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})},
		FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
		FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
		FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})},
		FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})},
	}};

	return descs;
}

llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module)
{
	auto&& desc = getEnvFuncDescs()[static_cast<size_t>(_id)];
	return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module);
}

llvm::Value* Ext::getArgAlloca()
{
	auto& a = m_argAllocas[m_argCounter++];
	if (!a)
	{
		// FIXME: Improve order and names
		InsertPointGuard g{getBuilder()};
		getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI());
		a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg");
	}

	return a;
}

llvm::Value* Ext::byPtr(llvm::Value* _value)
{
	auto a = getArgAlloca();
	getBuilder().CreateStore(_value, a);
	return a;
}

llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list<llvm::Value*> const& _args)
{
	auto& func = m_funcs[static_cast<size_t>(_funcId)];
	if (!func)
		func = createFunc(_funcId, getModule());

	m_argCounter = 0;
	return getBuilder().CreateCall(func, {_args.begin(), _args.size()});
}

llvm::Value* Ext::sload(llvm::Value* _index)
{
	auto ret = getArgAlloca();
	createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness
	return m_builder.CreateLoad(ret);
}

void Ext::sstore(llvm::Value* _index, llvm::Value* _value)
{
	createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness
}

llvm::Value* Ext::calldataload(llvm::Value* _index)
{
	auto ret = getArgAlloca();
	createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret});
	ret = m_builder.CreateLoad(ret);
	return Endianness::toNative(m_builder, ret);
}

llvm::Value* Ext::balance(llvm::Value* _address)
{
	auto address = Endianness::toBE(m_builder, _address);
	auto ret = getArgAlloca();
	createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret});
	return m_builder.CreateLoad(ret);
}

llvm::Value* Ext::blockhash(llvm::Value* _number)
{
	auto hash = getArgAlloca();
	createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash});
	hash =  m_builder.CreateLoad(hash);
	return Endianness::toNative(getBuilder(), hash);
}

llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
{
	auto gas = byPtr(_gas);
	auto ret = getArgAlloca();
	auto begin = m_memoryMan.getBytePtr(_initOff);
	auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
	createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret});
	_gas = m_builder.CreateLoad(gas); // Return gas
	llvm::Value* address = m_builder.CreateLoad(ret);
	address = Endianness::toNative(m_builder, address);
	return address;
}

llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress)
{
	auto gas = byPtr(_gas);
	auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress);
	auto inBeg = m_memoryMan.getBytePtr(_inOff);
	auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size");
	auto outBeg = m_memoryMan.getBytePtr(_outOff);
	auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
	auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
	auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
	_gas = m_builder.CreateLoad(gas); // Return gas
	return m_builder.CreateZExt(ret, Type::Word, "ret");
}

llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
{
	auto begin = m_memoryMan.getBytePtr(_inOff);
	auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size");
	auto ret = getArgAlloca();
	createCall(EnvFunc::sha3, {begin, size, ret});
	llvm::Value* hash = m_builder.CreateLoad(ret);
	hash = Endianness::toNative(m_builder, hash);
	return hash;
}

MemoryRef Ext::extcode(llvm::Value* _addr)
{
	auto addr = Endianness::toBE(m_builder, _addr);
	auto code = createCall(EnvFunc::extcode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size});
	auto codeSize = m_builder.CreateLoad(m_size);
	auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word);
	return {code, codeSize256};
}

void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array<llvm::Value*,4> const& _topics)
{
	auto begin = m_memoryMan.getBytePtr(_memIdx);
	auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size");
	llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, getArgAlloca(), getArgAlloca(), getArgAlloca(), getArgAlloca()};

	auto topicArgPtr = &args[3];
	for (auto&& topic : _topics)
	{
		if (topic)
			m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr);
		else
			*topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr);
		++topicArgPtr;
	}

	createCall(EnvFunc::log, {args[0], args[1], args[2], args[3], args[4], args[5], args[6]});  // TODO: use std::initializer_list<>
}

}
}
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommonJS.cpp
 * @authors:
 *   Gav Wood <i@gavwood.com>
 *   Marek Kotewicz <marek@ethdev.com>
 * @date 2014
 */

#include "CommonJS.h"

namespace dev
{

bytes jsToBytes(std::string const& _s)
{
	if (_s.substr(0, 2) == "0x")
		// Hex
		return fromHex(_s.substr(2));
	else if (_s.find_first_not_of("0123456789") == std::string::npos)
		// Decimal
		return toCompactBigEndian(bigint(_s));
	else
		return bytes();
}

bytes padded(bytes _b, unsigned _l)
{
	while (_b.size() < _l)
		_b.insert(_b.begin(), 0);
	while (_b.size() < _l)
		_b.push_back(0);
	return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
}

bytes unpadded(bytes _b)
{
	auto p = asString(_b).find_last_not_of((char)0);
	_b.resize(p == std::string::npos ? 0 : (p + 1));
	return _b;
}

std::string prettyU256(u256 _n)
{
	unsigned inc = 0;
	std::string raw;
	std::ostringstream s;
	if (!(_n >> 64))
		s << " " << (uint64_t)_n << " (0x" << (uint64_t)_n << ")";
	else if (!~(_n >> 64))
		s << " " << (int64_t)_n << " (0x" << (int64_t)_n << ")";
	else if ((_n >> 160) == 0)
	{
		Address a = right160(_n);

		std::string n = a.abridged();
		if (n.empty())
			s << "0x" << a;
		else
			s << n << "(0x" << a.abridged() << ")";
	}
	else if ((raw = fromRaw((h256)_n, &inc)).size())
		return "\"" + raw + "\"" + (inc ? " + " + std::to_string(inc) : "");
	else
		s << "" << (h256)_n;
	return s.str();
}

std::string fromRaw(h256 _n, unsigned* _inc)
{
	if (_n)
	{
		std::string s((char const*)_n.data(), 32);
		auto l = s.find_first_of('\0');
		if (!l)
			return NULL;
		if (l != std::string::npos)
		{
			auto p = s.find_first_not_of('\0', l);
			if (!(p == std::string::npos || (_inc && p == 31)))
				return NULL;
			if (_inc)
				*_inc = (byte)s[31];
			s.resize(l);
		}
		for (auto i: s)
			if (i < 32)
				return NULL;
		return s;
	}
	return NULL;
}

Address fromString(std::string _sn)
{
	if (_sn.size() > 32)
		_sn.resize(32);
	h256 n;
	memcpy(n.data(), _sn.data(), _sn.size());
	memset(n.data() + _sn.size(), 0, 32 - _sn.size());
	if (_sn.size() == 40)
		return Address(fromHex(_sn));
	else
		return Address();
		//we try to resolve the recipient adress using nameReg contract state
		/*const Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); //NameReg contract
		if (h160 nameReg = (u160)ethClient->stateAt(c_config, 0))
			if (h256 a = ethClient->stateAt(nameReg, n))
				return right160(a);*/
}

}
<commit_msg> - delete code comment (code used to resolve name using NameReg contract)<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommonJS.cpp
 * @authors:
 *   Gav Wood <i@gavwood.com>
 *   Marek Kotewicz <marek@ethdev.com>
 * @date 2014
 */

#include "CommonJS.h"

namespace dev
{

bytes jsToBytes(std::string const& _s)
{
	if (_s.substr(0, 2) == "0x")
		// Hex
		return fromHex(_s.substr(2));
	else if (_s.find_first_not_of("0123456789") == std::string::npos)
		// Decimal
		return toCompactBigEndian(bigint(_s));
	else
		return bytes();
}

bytes padded(bytes _b, unsigned _l)
{
	while (_b.size() < _l)
		_b.insert(_b.begin(), 0);
	while (_b.size() < _l)
		_b.push_back(0);
	return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
}

bytes unpadded(bytes _b)
{
	auto p = asString(_b).find_last_not_of((char)0);
	_b.resize(p == std::string::npos ? 0 : (p + 1));
	return _b;
}

std::string prettyU256(u256 _n)
{
	unsigned inc = 0;
	std::string raw;
	std::ostringstream s;
	if (!(_n >> 64))
		s << " " << (uint64_t)_n << " (0x" << (uint64_t)_n << ")";
	else if (!~(_n >> 64))
		s << " " << (int64_t)_n << " (0x" << (int64_t)_n << ")";
	else if ((_n >> 160) == 0)
	{
		Address a = right160(_n);

		std::string n = a.abridged();
		if (n.empty())
			s << "0x" << a;
		else
			s << n << "(0x" << a.abridged() << ")";
	}
	else if ((raw = fromRaw((h256)_n, &inc)).size())
		return "\"" + raw + "\"" + (inc ? " + " + std::to_string(inc) : "");
	else
		s << "" << (h256)_n;
	return s.str();
}

std::string fromRaw(h256 _n, unsigned* _inc)
{
	if (_n)
	{
		std::string s((char const*)_n.data(), 32);
		auto l = s.find_first_of('\0');
		if (!l)
			return NULL;
		if (l != std::string::npos)
		{
			auto p = s.find_first_not_of('\0', l);
			if (!(p == std::string::npos || (_inc && p == 31)))
				return NULL;
			if (_inc)
				*_inc = (byte)s[31];
			s.resize(l);
		}
		for (auto i: s)
			if (i < 32)
				return NULL;
		return s;
	}
	return NULL;
}

Address fromString(std::string _sn)
{
	if (_sn.size() > 32)
		_sn.resize(32);
	h256 n;
	memcpy(n.data(), _sn.data(), _sn.size());
	memset(n.data() + _sn.size(), 0, 32 - _sn.size());
	if (_sn.size() == 40)
		return Address(fromHex(_sn));
	else
		return Address();
}

}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
 * @author Alex Leverington <nessence@gmail.com>
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include <random>
#include <chrono>
#include <thread>
#include <mutex>
#include <libdevcore/Guards.h>
#include "SHA3.h"
#include "FileSystem.h"
#include "CryptoPP.h"
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::crypto;

static Secp256k1 s_secp256k1;

bool dev::SignatureStruct::isValid() const
{
	if (v > 1 ||
		r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
		s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
		s < h256("0x0000000000000000000000000000000000000000000000000000000000000001") ||
		r < h256("0x0000000000000000000000000000000000000000000000000000000000000001"))
		return false;
	return true;
}

Address dev::ZeroAddress = Address();

Public dev::toPublic(Secret const& _secret)
{
	Public p;
	s_secp256k1.toPublic(_secret, p);
	return std::move(p);
}

Address dev::toAddress(Public const& _public)
{
	return s_secp256k1.toAddress(_public);
}

Address dev::toAddress(Secret const& _secret)
{
	Public p;
	s_secp256k1.toPublic(_secret, p);
	return s_secp256k1.toAddress(p);
}

void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	bytes io = _plain.toBytes();
	s_secp256k1.encrypt(_k, io);
	o_cipher = std::move(io);
}

bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{
	bytes io = _cipher.toBytes();
	s_secp256k1.decrypt(_k, io);
	if (io.empty())
		return false;
	o_plaintext = std::move(io);
	return true;
}

void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	bytes io = _plain.toBytes();
	s_secp256k1.encryptECIES(_k, io);
	o_cipher = std::move(io);
}

bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{
	bytes io = _cipher.toBytes();
	if (!s_secp256k1.decryptECIES(_k, io))
		return false;
	o_plaintext = std::move(io);
	return true;
}

void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	// TOOD: @alex @subtly do this properly.
	encrypt(KeyPair(_k).pub(), _plain, o_cipher);
}

bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
{
	// TODO: @alex @subtly do this properly.
	return decrypt(_k, _cipher, o_plain);
}

h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	h128 iv(Nonce::get());
	return encryptSymNoAuth(_k, _plain, o_cipher, iv);
}

h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
{
	o_cipher.resize(_plain.size());

	const int c_aesKeyLen = 16;
	SecByteBlock key(_k.data(), c_aesKeyLen);
	try
	{
		CTR_Mode<AES>::Encryption e;
		e.SetKeyWithIV(key, key.size(), _iv.data());
		e.ProcessData(o_cipher.data(), _plain.data(), _plain.size());
		return _iv;
	}
	catch (CryptoPP::Exception& _e)
	{
		cerr << _e.what() << endl;
		o_cipher.resize(0);
		return h128();
	}
}

bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
{
	o_plaintext.resize(_cipher.size());

	const size_t c_aesKeyLen = 16;
	SecByteBlock key(_k.data(), c_aesKeyLen);
	try
	{
		CTR_Mode<AES>::Decryption d;
		d.SetKeyWithIV(key, key.size(), _iv.data());
		d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size());
		return true;
	}
	catch (CryptoPP::Exception& _e)
	{
		cerr << _e.what() << endl;
		o_plaintext.resize(0);
		return false;
	}
}

Public dev::recover(Signature const& _sig, h256 const& _message)
{
	return s_secp256k1.recover(_sig, _message.ref());
}

Signature dev::sign(Secret const& _k, h256 const& _hash)
{
	return s_secp256k1.sign(_k, _hash);
}

bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
{
	return s_secp256k1.verify(_p, _s, _hash.ref(), true);
}

KeyPair KeyPair::create()
{
	static boost::thread_specific_ptr<mt19937_64> s_eng;
	static unsigned s_id = 0;
	if (!s_eng.get())
		s_eng.reset(new mt19937_64(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count() + ++s_id));

	uniform_int_distribution<uint16_t> d(0, 255);

	for (int i = 0; i < 100; ++i)
	{
		KeyPair ret(FixedHash<32>::random(*s_eng.get()));
		if (ret.address())
			return ret;
	}
	return KeyPair();
}

KeyPair::KeyPair(h256 _sec):
	m_secret(_sec)
{
	if (s_secp256k1.verifySecret(m_secret, m_public))
		m_address = s_secp256k1.toAddress(m_public);
}

KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{
	return KeyPair(sha3(aesDecrypt(_seed, _password)));
}

h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
{
	// H(H(r||k)^h)
	h256 s;
	sha3mac(Nonce::get().ref(), _priv.ref(), s.ref());
	s ^= _hash;
	sha3(s.ref(), s.ref());

	if (!s || !_hash || !_priv)
		BOOST_THROW_EXCEPTION(InvalidState());
	return std::move(s);
}

h256 Nonce::get(bool _commit)
{
	// todo: atomic efface bit, periodic save, kdf, rr, rng
	// todo: encrypt
	static h256 s_seed;
	static string s_seedFile(getDataDir() + "/seed");
	static mutex s_x;
	Guard l(s_x);
	if (!s_seed)
	{
		static Nonce s_nonce;
		bytes b = contents(s_seedFile);
		if (b.size() == 32)
			memcpy(s_seed.data(), b.data(), 32);
		else
		{
			// todo: replace w/entropy from user and system
			std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
			std::uniform_int_distribution<uint16_t> d(0, 255);
			for (unsigned i = 0; i < 32; ++i)
				s_seed[i] = (byte)d(s_eng);
		}
		if (!s_seed)
			BOOST_THROW_EXCEPTION(InvalidState());

		// prevent seed reuse if process terminates abnormally
		writeFile(s_seedFile, bytes());
	}
	h256 prev(s_seed);
	sha3(prev.ref(), s_seed.ref());
	if (_commit)
		writeFile(s_seedFile, s_seed.asBytes());
	return std::move(s_seed);
}

Nonce::~Nonce()
{
	Nonce::get(true);
}
<commit_msg>issues: r, s < 1<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
 * @author Alex Leverington <nessence@gmail.com>
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include <random>
#include <chrono>
#include <thread>
#include <mutex>
#include <libdevcore/Guards.h>
#include "SHA3.h"
#include "FileSystem.h"
#include "CryptoPP.h"
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::crypto;

static Secp256k1 s_secp256k1;

bool dev::SignatureStruct::isValid() const
{
	if (v > 1 ||
		r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
		s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
		s < h256(1) ||
		r < h256(1))
		return false;
	return true;
}

Address dev::ZeroAddress = Address();

Public dev::toPublic(Secret const& _secret)
{
	Public p;
	s_secp256k1.toPublic(_secret, p);
	return std::move(p);
}

Address dev::toAddress(Public const& _public)
{
	return s_secp256k1.toAddress(_public);
}

Address dev::toAddress(Secret const& _secret)
{
	Public p;
	s_secp256k1.toPublic(_secret, p);
	return s_secp256k1.toAddress(p);
}

void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	bytes io = _plain.toBytes();
	s_secp256k1.encrypt(_k, io);
	o_cipher = std::move(io);
}

bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{
	bytes io = _cipher.toBytes();
	s_secp256k1.decrypt(_k, io);
	if (io.empty())
		return false;
	o_plaintext = std::move(io);
	return true;
}

void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	bytes io = _plain.toBytes();
	s_secp256k1.encryptECIES(_k, io);
	o_cipher = std::move(io);
}

bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{
	bytes io = _cipher.toBytes();
	if (!s_secp256k1.decryptECIES(_k, io))
		return false;
	o_plaintext = std::move(io);
	return true;
}

void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	// TOOD: @alex @subtly do this properly.
	encrypt(KeyPair(_k).pub(), _plain, o_cipher);
}

bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
{
	// TODO: @alex @subtly do this properly.
	return decrypt(_k, _cipher, o_plain);
}

h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
	h128 iv(Nonce::get());
	return encryptSymNoAuth(_k, _plain, o_cipher, iv);
}

h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
{
	o_cipher.resize(_plain.size());

	const int c_aesKeyLen = 16;
	SecByteBlock key(_k.data(), c_aesKeyLen);
	try
	{
		CTR_Mode<AES>::Encryption e;
		e.SetKeyWithIV(key, key.size(), _iv.data());
		e.ProcessData(o_cipher.data(), _plain.data(), _plain.size());
		return _iv;
	}
	catch (CryptoPP::Exception& _e)
	{
		cerr << _e.what() << endl;
		o_cipher.resize(0);
		return h128();
	}
}

bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
{
	o_plaintext.resize(_cipher.size());

	const size_t c_aesKeyLen = 16;
	SecByteBlock key(_k.data(), c_aesKeyLen);
	try
	{
		CTR_Mode<AES>::Decryption d;
		d.SetKeyWithIV(key, key.size(), _iv.data());
		d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size());
		return true;
	}
	catch (CryptoPP::Exception& _e)
	{
		cerr << _e.what() << endl;
		o_plaintext.resize(0);
		return false;
	}
}

Public dev::recover(Signature const& _sig, h256 const& _message)
{
	return s_secp256k1.recover(_sig, _message.ref());
}

Signature dev::sign(Secret const& _k, h256 const& _hash)
{
	return s_secp256k1.sign(_k, _hash);
}

bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
{
	return s_secp256k1.verify(_p, _s, _hash.ref(), true);
}

KeyPair KeyPair::create()
{
	static boost::thread_specific_ptr<mt19937_64> s_eng;
	static unsigned s_id = 0;
	if (!s_eng.get())
		s_eng.reset(new mt19937_64(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count() + ++s_id));

	uniform_int_distribution<uint16_t> d(0, 255);

	for (int i = 0; i < 100; ++i)
	{
		KeyPair ret(FixedHash<32>::random(*s_eng.get()));
		if (ret.address())
			return ret;
	}
	return KeyPair();
}

KeyPair::KeyPair(h256 _sec):
	m_secret(_sec)
{
	if (s_secp256k1.verifySecret(m_secret, m_public))
		m_address = s_secp256k1.toAddress(m_public);
}

KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{
	return KeyPair(sha3(aesDecrypt(_seed, _password)));
}

h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
{
	// H(H(r||k)^h)
	h256 s;
	sha3mac(Nonce::get().ref(), _priv.ref(), s.ref());
	s ^= _hash;
	sha3(s.ref(), s.ref());

	if (!s || !_hash || !_priv)
		BOOST_THROW_EXCEPTION(InvalidState());
	return std::move(s);
}

h256 Nonce::get(bool _commit)
{
	// todo: atomic efface bit, periodic save, kdf, rr, rng
	// todo: encrypt
	static h256 s_seed;
	static string s_seedFile(getDataDir() + "/seed");
	static mutex s_x;
	Guard l(s_x);
	if (!s_seed)
	{
		static Nonce s_nonce;
		bytes b = contents(s_seedFile);
		if (b.size() == 32)
			memcpy(s_seed.data(), b.data(), 32);
		else
		{
			// todo: replace w/entropy from user and system
			std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
			std::uniform_int_distribution<uint16_t> d(0, 255);
			for (unsigned i = 0; i < 32; ++i)
				s_seed[i] = (byte)d(s_eng);
		}
		if (!s_seed)
			BOOST_THROW_EXCEPTION(InvalidState());

		// prevent seed reuse if process terminates abnormally
		writeFile(s_seedFile, bytes());
	}
	h256 prev(s_seed);
	sha3(prev.ref(), s_seed.ref());
	if (_commit)
		writeFile(s_seedFile, s_seed.asBytes());
	return std::move(s_seed);
}

Nonce::~Nonce()
{
	Nonce::get(true);
}
<|endoftext|>


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

#include <fstream>
#include "cgengine.h"
#include <votca/tools/tokenizer.h>
#include "version.h"

namespace po = boost::program_options;

CGEngine::CGEngine()
    : _op_desc("Allowed options"), _op_desc_specific("Specific options")
{
    InitializeStandardOptions();
}

CGEngine::~CGEngine()
{
    map<string, CGMoleculeDef *>::iterator i;
    for(i=_molecule_defs.begin(); i!=_molecule_defs.end();++i)
        delete (*i).second;
    _molecule_defs.clear();
}

void CGEngine::Initialize()
{
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();
}

void CGEngine::ParseCommandLine(int argc, char **argv)
{
    _op_desc.add(_op_desc_specific);
    namespace po=boost::program_options;
    try {
        po::store(po::parse_command_line(argc, argv, _op_desc), _op_vm);
        po::notify(_op_vm);
    }
    catch(boost::program_options::error err) {
        throw runtime_error(string("error parsing command line: ") + err.what());
    }
}

/**
    \todo melts with different molecules
*/
TopologyMap *CGEngine::CreateCGTopology(Topology &in, Topology &out)
{
    MoleculeContainer &mols = in.Molecules();
    MoleculeContainer::iterator iter;
    TopologyMap *m = new TopologyMap(&in, &out);
    for(iter=mols.begin(); iter!=mols.end(); ++iter) {
        Molecule *mol = *iter;
        CGMoleculeDef *def = getMoleculeDef(mol->getName());
        if(!def) {
            cout << "--------------------------------------\n"
                 << "WARNING: unknown molecule \"" << mol->getName() << "\" with id "
                 << mol->getId() << " in topology" << endl
                 << "molecule will not be mapped to CG representation\n"
                 << "Check weather a mapping file for all molecule exists, was specified in --cg "
                 << "separated by ; and the ident tag in xml-file matches the molecule name\n"
                 << "--------------------------------------\n";
            continue;
        }
        Molecule *mcg = def->CreateMolecule(out);
        Map *map = def->CreateMap(*mol, *mcg);
        m->AddMoleculeMap(map);
    }
    out.RebuildExclusions();
    return m;
}

void CGEngine::LoadMoleculeType(string filename)
{
    Tokenizer tok(filename, ";");
    Tokenizer::iterator iter;

    for(iter=tok.begin(); iter!=tok.end(); ++iter) {
        CGMoleculeDef *def = new CGMoleculeDef();
        string  file = *iter;
        boost::trim(file);
        def->Load(file);
        _molecule_defs[def->getIdent()] = def;
    }
}

void CGEngine::BeginCG(Topology &top)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->BeginCG(&top);
}

void CGEngine::EndCG()
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EndCG();
}

void CGEngine::EvalConfiguration(Topology &top_cg)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EvalConfiguration(&top_cg);
}

void CGEngine::InitializeStandardOptions()
{
    po::options_description trj("Trajectory options");
    _op_desc.add_options()
    ("help", "  produce this help message")
    ("top", boost::program_options::value<string>(), "  atomistic topology file")
    ("cg", boost::program_options::value<string>(), "  coarse graining definitions (xml-file)")
    ;

    trj.add_options()
    ("trj", boost::program_options::value<string>(), "  atomistic trajectory file")
    ("begin", boost::program_options::value<double>()->default_value(0.0), "  skip frames before this time")
    ("first-frame", boost::program_options::value<int>()->default_value(0), "  start with this frame")
    ("nframes", boost::program_options::value<int>(), "  process so many frames")
    ;

    _op_desc.add(trj);
}

void CGEngine::Run()
{
    TopologyReader *reader;
    TrajectoryReader *traj_reader;
    Topology top;
    Topology top_cg;
    TopologyMap *map;
    double begin;
    int first_frame;

    bool has_begin=false;

//    if (vm.count("version")) {
//        votca::csg::HelpTextHeader("csg");
//        exit(0);
//    }

    if (!_op_vm.count("top")) {
        cout << _op_desc << endl;
        throw runtime_error("no topology file specified");
    }
    if (!_op_vm.count("cg")) {
        cout << _op_desc << endl;
        throw runtime_error("no coarse graining definition specified");
    }

    if(_op_vm.count("begin")) {
        has_begin = true;
        begin = _op_vm["begin"].as<double>();
    }

    int nframes = -1;
    if(_op_vm.count("nframes")) {
        nframes = _op_vm["nframes"].as<int>();
    }

    first_frame = _op_vm["first-frame"].as<int>();

    // create reader for atomistic topology
    reader = TopReaderFactory().Create(_op_vm["top"].as<string>());
    if(reader == NULL)
        throw runtime_error(string("input format not supported: ") + _op_vm["top"].as<string>());

    // read in the atomistic topology
    reader->ReadTopology(_op_vm["top"].as<string>(), top);
    cout << "I have " << top.BeadCount() << " beads in " << top.MoleculeCount() << " molecules" << endl;
    top.CheckMoleculeNaming();

    //top.CreateMoleculesByResidue();
    //top.CreateOneBigMolecule("PS1");

    // read in the coarse graining definitions (xml files)
    LoadMoleculeType(_op_vm["cg"].as<string>());
    // create the mapping + cg topology
    map = CreateCGTopology(top, top_cg);
    //cg_def.CreateMolecule(top_cg);

    cout << "I have " << top_cg.BeadCount() << " beads in " << top_cg.MoleculeCount() << " molecules for the coarsegraining" << endl;

    // if trj is given, process trajectory file
    if (_op_vm.count("trj")) {
        // create reader for trajectory
        traj_reader = TrjReaderFactory().Create(_op_vm["trj"].as<string>());
        if(traj_reader == NULL)
            throw runtime_error(string("input format not supported: ") + _op_vm["trj"].as<string>());
        // open the trajectory
        traj_reader->Open(_op_vm["trj"].as<string>());
        // read in first frame
        traj_reader->FirstFrame(top);

        // notify all observer that coarse graining has begun

        map->Apply();
        BeginCG(top_cg);

        for(bool bok=true; bok==true; bok = traj_reader->NextFrame(top)) {
            if(((top.getTime() < begin) && has_begin)|| first_frame > 0) {
                first_frame--;
                continue;
            }
            if(nframes == 0 ) break;
            map->Apply();
            EvalConfiguration(top_cg);
            nframes--;
        }
        EndCG();
        traj_reader->Close();
    }
    delete traj_reader;
    delete reader;
    delete map;
}
<commit_msg>fixed first frame option<commit_after>/*
 * Copyright 2009 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <fstream>
#include "cgengine.h"
#include <votca/tools/tokenizer.h>
#include "version.h"

namespace po = boost::program_options;

CGEngine::CGEngine()
    : _op_desc("Allowed options"), _op_desc_specific("Specific options")
{
    InitializeStandardOptions();
}

CGEngine::~CGEngine()
{
    map<string, CGMoleculeDef *>::iterator i;
    for(i=_molecule_defs.begin(); i!=_molecule_defs.end();++i)
        delete (*i).second;
    _molecule_defs.clear();
}

void CGEngine::Initialize()
{
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();
}

void CGEngine::ParseCommandLine(int argc, char **argv)
{
    _op_desc.add(_op_desc_specific);
    namespace po=boost::program_options;
    try {
        po::store(po::parse_command_line(argc, argv, _op_desc), _op_vm);
        po::notify(_op_vm);
    }
    catch(boost::program_options::error err) {
        throw runtime_error(string("error parsing command line: ") + err.what());
    }
}

/**
    \todo melts with different molecules
*/
TopologyMap *CGEngine::CreateCGTopology(Topology &in, Topology &out)
{
    MoleculeContainer &mols = in.Molecules();
    MoleculeContainer::iterator iter;
    TopologyMap *m = new TopologyMap(&in, &out);
    for(iter=mols.begin(); iter!=mols.end(); ++iter) {
        Molecule *mol = *iter;
        CGMoleculeDef *def = getMoleculeDef(mol->getName());
        if(!def) {
            cout << "--------------------------------------\n"
                 << "WARNING: unknown molecule \"" << mol->getName() << "\" with id "
                 << mol->getId() << " in topology" << endl
                 << "molecule will not be mapped to CG representation\n"
                 << "Check weather a mapping file for all molecule exists, was specified in --cg "
                 << "separated by ; and the ident tag in xml-file matches the molecule name\n"
                 << "--------------------------------------\n";
            continue;
        }
        Molecule *mcg = def->CreateMolecule(out);
        Map *map = def->CreateMap(*mol, *mcg);
        m->AddMoleculeMap(map);
    }
    out.RebuildExclusions();
    return m;
}

void CGEngine::LoadMoleculeType(string filename)
{
    Tokenizer tok(filename, ";");
    Tokenizer::iterator iter;

    for(iter=tok.begin(); iter!=tok.end(); ++iter) {
        CGMoleculeDef *def = new CGMoleculeDef();
        string  file = *iter;
        boost::trim(file);
        def->Load(file);
        _molecule_defs[def->getIdent()] = def;
    }
}

void CGEngine::BeginCG(Topology &top)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->BeginCG(&top);
}

void CGEngine::EndCG()
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EndCG();
}

void CGEngine::EvalConfiguration(Topology &top_cg)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EvalConfiguration(&top_cg);
}

void CGEngine::InitializeStandardOptions()
{
    po::options_description trj("Trajectory options");
    _op_desc.add_options()
    ("help", "  produce this help message")
    ("top", boost::program_options::value<string>(), "  atomistic topology file")
    ("cg", boost::program_options::value<string>(), "  coarse graining definitions (xml-file)")
    ;

    trj.add_options()
    ("trj", boost::program_options::value<string>(), "  atomistic trajectory file")
    ("begin", boost::program_options::value<double>()->default_value(0.0), "  skip frames before this time")
    ("first-frame", boost::program_options::value<int>()->default_value(0), "  start with this frame")
    ("nframes", boost::program_options::value<int>(), "  process so many frames")
    ;

    _op_desc.add(trj);
}

void CGEngine::Run()
{
    TopologyReader *reader;
    TrajectoryReader *traj_reader;
    Topology top;
    Topology top_cg;
    TopologyMap *map;
    double begin;
    int first_frame;

    bool has_begin=false;

//    if (vm.count("version")) {
//        votca::csg::HelpTextHeader("csg");
//        exit(0);
//    }

    if (!_op_vm.count("top")) {
        cout << _op_desc << endl;
        throw runtime_error("no topology file specified");
    }
    if (!_op_vm.count("cg")) {
        cout << _op_desc << endl;
        throw runtime_error("no coarse graining definition specified");
    }

    if(_op_vm.count("begin")) {
        has_begin = true;
        begin = _op_vm["begin"].as<double>();
    }

    int nframes = -1;
    if(_op_vm.count("nframes")) {
        nframes = _op_vm["nframes"].as<int>();
    }

    first_frame = _op_vm["first-frame"].as<int>();

    // create reader for atomistic topology
    reader = TopReaderFactory().Create(_op_vm["top"].as<string>());
    if(reader == NULL)
        throw runtime_error(string("input format not supported: ") + _op_vm["top"].as<string>());

    // read in the atomistic topology
    reader->ReadTopology(_op_vm["top"].as<string>(), top);
    cout << "I have " << top.BeadCount() << " beads in " << top.MoleculeCount() << " molecules" << endl;
    top.CheckMoleculeNaming();

    //top.CreateMoleculesByResidue();
    //top.CreateOneBigMolecule("PS1");

    // read in the coarse graining definitions (xml files)
    LoadMoleculeType(_op_vm["cg"].as<string>());
    // create the mapping + cg topology
    map = CreateCGTopology(top, top_cg);
    //cg_def.CreateMolecule(top_cg);

    cout << "I have " << top_cg.BeadCount() << " beads in " << top_cg.MoleculeCount() << " molecules for the coarsegraining" << endl;

    // if trj is given, process trajectory file
    if (_op_vm.count("trj")) {
        // create reader for trajectory
        traj_reader = TrjReaderFactory().Create(_op_vm["trj"].as<string>());
        if(traj_reader == NULL)
            throw runtime_error(string("input format not supported: ") + _op_vm["trj"].as<string>());
        // open the trajectory
        traj_reader->Open(_op_vm["trj"].as<string>());
        // read in first frame
        traj_reader->FirstFrame(top);

        // notify all observer that coarse graining has begun

        map->Apply();
        BeginCG(top_cg);

        for(bool bok=true; bok==true; bok = traj_reader->NextFrame(top)) {
            if(((top.getTime() < begin) && has_begin)|| first_frame > 1) {
                first_frame--;
                continue;
            }
            if(nframes == 0 ) break;
            map->Apply();
            EvalConfiguration(top_cg);
            nframes--;
        }
        EndCG();
        traj_reader->Close();
    }
    delete traj_reader;
    delete reader;
    delete map;
}
<|endoftext|>


<commit_before> //
// File:   topology.cc
// Author: ruehle
//
// Created on April 5, 2007, 12:30 PM
//

#include "topology.h"
#include <tools/rangeparser.h>
#include "interaction.h"

Topology::~Topology()
{
    Cleanup();
}

void Topology::Cleanup()
{
    // cleanup beads
    {
        BeadContainer::iterator i;
        for(i=_beads.begin();i<_beads.end();++i)
            delete *i;
        _beads.clear();
    }
    // cleanup molecules
    {
        MoleculeContainer::iterator i;
        for(i=_molecules.begin();i<_molecules.end();++i)
            delete *i;
        _molecules.clear();
    }
    // cleanup residues
    {
        ResidueContainer::iterator i;
        for(i=_residues.begin();i<_residues.end();++i)
            delete (*i);
        _residues.clear();
    }
    // cleanup interactions
    {
        InteractionContainer::iterator i;
        for(i=_interactions.begin();i<_interactions.end();++i)
            delete (*i);
        _interactions.clear();
    }
}

/// \todo implement checking!!
void Topology::CreateMoleculesByRange(string name, int first, int nbeads, int nmolecules)
{
    Molecule *mol = CreateMolecule(name);
    int beadcount=0;

    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        while(--first > 0) continue;
        string bname = //lexical_cast<string>(mol->getId()) + ":"
                      //lexical_cast<string>(bead->Residue()) + ":"
                      //+
                      (*bead)->getName();
        cout << "adding " << bname << " to " << name << endl;
        mol->AddBead((*bead), bname);
        if(++beadcount == nbeads) {
            if(--nmolecules <= 0) break;
            mol = CreateMolecule(name);
            beadcount = 0;
        }
    }
}

/// \todo clean up CreateMoleculesByResidue!
void Topology::CreateMoleculesByResidue()
{
    // first create a molecule for each residue
    ResidueContainer::iterator res;
    for(res=_residues.begin(); res!=_residues.end(); ++res) {
        CreateMolecule((*res)->getName());
    }

    // add the beads to the corresponding molecules based on their resid
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        //MoleculeByIndex((*bead)->getResnr())->AddBead((*bead)->getId(), (*bead)->getName());

        MoleculeByIndex((*bead)->getResnr())->AddBead((*bead), string("1:TRI:") + (*bead)->getName());
    }

    /// \todo sort beads in molecules that all beads are stored in the same order. This is needed for the mapping!
}

void Topology::CreateOneBigMolecule(string name)
{
    Molecule *mi = CreateMolecule(name);

    BeadContainer::iterator bead;

    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        stringstream n("");
        n << (*bead)->getResnr() +1 << ":" <<  _residues[(*bead)->getResnr()]->getName() << ":" << (*bead)->getName();
        //cout << n.str() << endl;
        mi->AddBead((*bead), n.str());
    }
}

void Topology::Add(Topology *top)
{
    BeadContainer::iterator bead;
    ResidueContainer::iterator res;
    MoleculeContainer::iterator mol;

    int bead0=BeadCount();
    int res0=ResidueCount();
    int mol0=MoleculeCount();

    for(bead=top->_beads.begin(); bead!=top->_beads.end(); ++bead) {
        Bead *bi = *bead;
        BeadType *type =  GetOrCreateBeadType(bi->getType()->getName());
        CreateBead(bi->getSymmetry(), bi->getName(), type, bi->getResnr()+res0, bi->getM(), bi->getQ());
    }

    for(res=top->_residues.begin();res!=top->_residues.end(); ++res) {
        CreateResidue((*res)->getName());
    }

    // \todo beadnames in molecules!!
    for(mol=top->_molecules.begin();mol!=top->_molecules.end(); ++mol) {
        Molecule *mi = CreateMolecule((*mol)->getName());
        for(int i=0; i<mi->BeadCount(); i++) {
            mi->AddBead(mi->getBead(i), "invalid");
        }
    }
}

void Topology::RenameMolecules(string range, string name)
{
    RangeParser rp;
    RangeParser::iterator i;

    rp.Parse(range);
    for(i=rp.begin();i!=rp.end();++i) {
        getMolecule(*i-1)->setName(name);
    }
}

void Topology::AddBondedInteraction(Interaction *ic)
{
    map<string,int>::iterator iter;
    iter = _interaction_groups.find(ic->getGroup());
    if(iter!=_interaction_groups.end())
        ic->setGroupId((*iter).second);
    else {
        int i= _interaction_groups.size();
        _interaction_groups[ic->getGroup()] = i;
        ic->setGroupId(i);
    }
    _interactions.push_back(ic);
}

BeadType *Topology::GetOrCreateBeadType(string name)
{
    map<string, int>::iterator iter;

    iter = _beadtype_map.find(name);
    if(iter == _beadtype_map.end()) {
        BeadType *bt = new BeadType(this, _beadtypes.size(), name);
        _beadtypes.push_back(bt);
        _beadtype_map[name] = bt->getId();
        return bt;
    }
    else {
        return _beadtypes[(*iter).second];
    }
    return NULL;
}

vec Topology::getDist(int bead1, int bead2) const
{
    vec r_tp, r_dp, r_sp, r_ij;
    vec r_i = getBead(bead1)->getPos();
    vec r_j = getBead(bead2)->getPos();
    vec a = _box.getCol(0); vec b = _box.getCol(1); vec c = _box.getCol(2);
    r_tp = r_j - r_i;
    r_dp = r_tp - c*round(r_tp.getZ()/c.getZ());
    r_sp = r_dp - b*round(r_dp.getY()/b.getY());
    r_ij = r_sp - a*round(r_sp.getX()/a.getX());
    return r_ij;
}

double Topology::BoxVolume()
{
    vec a = _box.getCol(0); vec b = _box.getCol(1); vec c = _box.getCol(2);
    return (a^b)*c;
}

<commit_msg>removed nasty debug message<commit_after> //
// File:   topology.cc
// Author: ruehle
//
// Created on April 5, 2007, 12:30 PM
//

#include "topology.h"
#include <tools/rangeparser.h>
#include "interaction.h"

Topology::~Topology()
{
    Cleanup();
}

void Topology::Cleanup()
{
    // cleanup beads
    {
        BeadContainer::iterator i;
        for(i=_beads.begin();i<_beads.end();++i)
            delete *i;
        _beads.clear();
    }
    // cleanup molecules
    {
        MoleculeContainer::iterator i;
        for(i=_molecules.begin();i<_molecules.end();++i)
            delete *i;
        _molecules.clear();
    }
    // cleanup residues
    {
        ResidueContainer::iterator i;
        for(i=_residues.begin();i<_residues.end();++i)
            delete (*i);
        _residues.clear();
    }
    // cleanup interactions
    {
        InteractionContainer::iterator i;
        for(i=_interactions.begin();i<_interactions.end();++i)
            delete (*i);
        _interactions.clear();
    }
}

/// \todo implement checking!!
void Topology::CreateMoleculesByRange(string name, int first, int nbeads, int nmolecules)
{
    Molecule *mol = CreateMolecule(name);
    int beadcount=0;

    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        while(--first > 0) continue;
        string bname = //lexical_cast<string>(mol->getId()) + ":"
                      //lexical_cast<string>(bead->Residue()) + ":"
                      //+
                      (*bead)->getName();
        mol->AddBead((*bead), bname);
        if(++beadcount == nbeads) {
            if(--nmolecules <= 0) break;
            mol = CreateMolecule(name);
            beadcount = 0;
        }
    }
}

/// \todo clean up CreateMoleculesByResidue!
void Topology::CreateMoleculesByResidue()
{
    // first create a molecule for each residue
    ResidueContainer::iterator res;
    for(res=_residues.begin(); res!=_residues.end(); ++res) {
        CreateMolecule((*res)->getName());
    }

    // add the beads to the corresponding molecules based on their resid
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        //MoleculeByIndex((*bead)->getResnr())->AddBead((*bead)->getId(), (*bead)->getName());

        MoleculeByIndex((*bead)->getResnr())->AddBead((*bead), string("1:TRI:") + (*bead)->getName());
    }

    /// \todo sort beads in molecules that all beads are stored in the same order. This is needed for the mapping!
}

void Topology::CreateOneBigMolecule(string name)
{
    Molecule *mi = CreateMolecule(name);

    BeadContainer::iterator bead;

    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        stringstream n("");
        n << (*bead)->getResnr() +1 << ":" <<  _residues[(*bead)->getResnr()]->getName() << ":" << (*bead)->getName();
        //cout << n.str() << endl;
        mi->AddBead((*bead), n.str());
    }
}

void Topology::Add(Topology *top)
{
    BeadContainer::iterator bead;
    ResidueContainer::iterator res;
    MoleculeContainer::iterator mol;

    int bead0=BeadCount();
    int res0=ResidueCount();
    int mol0=MoleculeCount();

    for(bead=top->_beads.begin(); bead!=top->_beads.end(); ++bead) {
        Bead *bi = *bead;
        BeadType *type =  GetOrCreateBeadType(bi->getType()->getName());
        CreateBead(bi->getSymmetry(), bi->getName(), type, bi->getResnr()+res0, bi->getM(), bi->getQ());
    }

    for(res=top->_residues.begin();res!=top->_residues.end(); ++res) {
        CreateResidue((*res)->getName());
    }

    // \todo beadnames in molecules!!
    for(mol=top->_molecules.begin();mol!=top->_molecules.end(); ++mol) {
        Molecule *mi = CreateMolecule((*mol)->getName());
        for(int i=0; i<mi->BeadCount(); i++) {
            mi->AddBead(mi->getBead(i), "invalid");
        }
    }
}

void Topology::RenameMolecules(string range, string name)
{
    RangeParser rp;
    RangeParser::iterator i;

    rp.Parse(range);
    for(i=rp.begin();i!=rp.end();++i) {
        getMolecule(*i-1)->setName(name);
    }
}

void Topology::AddBondedInteraction(Interaction *ic)
{
    map<string,int>::iterator iter;
    iter = _interaction_groups.find(ic->getGroup());
    if(iter!=_interaction_groups.end())
        ic->setGroupId((*iter).second);
    else {
        int i= _interaction_groups.size();
        _interaction_groups[ic->getGroup()] = i;
        ic->setGroupId(i);
    }
    _interactions.push_back(ic);
}

BeadType *Topology::GetOrCreateBeadType(string name)
{
    map<string, int>::iterator iter;

    iter = _beadtype_map.find(name);
    if(iter == _beadtype_map.end()) {
        BeadType *bt = new BeadType(this, _beadtypes.size(), name);
        _beadtypes.push_back(bt);
        _beadtype_map[name] = bt->getId();
        return bt;
    }
    else {
        return _beadtypes[(*iter).second];
    }
    return NULL;
}

vec Topology::getDist(int bead1, int bead2) const
{
    vec r_tp, r_dp, r_sp, r_ij;
    vec r_i = getBead(bead1)->getPos();
    vec r_j = getBead(bead2)->getPos();
    vec a = _box.getCol(0); vec b = _box.getCol(1); vec c = _box.getCol(2);
    r_tp = r_j - r_i;
    r_dp = r_tp - c*round(r_tp.getZ()/c.getZ());
    r_sp = r_dp - b*round(r_dp.getY()/b.getY());
    r_ij = r_sp - a*round(r_sp.getX()/a.getX());
    return r_ij;
}

double Topology::BoxVolume()
{
    vec a = _box.getCol(0); vec b = _box.getCol(1); vec c = _box.getCol(2);
    return (a^b)*c;
}

<|endoftext|>


<commit_before><commit_msg>Fix memory leak in tips handler.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 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 "chrome/browser/omnibox_search_hint.h"

#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/task.h"
// TODO(avi): remove when conversions not needed any more
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/browser/tab_contents/navigation_details.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
#include "content/common/notification_type.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources_standard.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"

// The URLs of search engines for which we want to trigger the infobar.
const char* kSearchEngineURLs[] = {
    "http://www.google.com/",
    "http://www.yahoo.com/",
    "http://www.bing.com/",
    "http://www.altavista.com/",
    "http://www.ask.com/",
    "http://www.wolframalpha.com/",
};

// HintInfoBar ----------------------------------------------------------------

class HintInfoBar : public ConfirmInfoBarDelegate {
 public:
  explicit HintInfoBar(OmniboxSearchHint* omnibox_hint);

 private:
  virtual ~HintInfoBar();

  void AllowExpiry() { should_expire_ = true; }

  // ConfirmInfoBarDelegate:
  virtual bool ShouldExpire(
      const content::LoadCommittedDetails& details) const OVERRIDE;
  virtual void InfoBarDismissed() OVERRIDE;
  virtual gfx::Image* GetIcon() const OVERRIDE;
  virtual Type GetInfoBarType() const OVERRIDE;
  virtual string16 GetMessageText() const OVERRIDE;
  virtual int GetButtons() const OVERRIDE;
  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
  virtual bool Accept() OVERRIDE;

  // The omnibox hint that shows us.
  OmniboxSearchHint* omnibox_hint_;

  // Whether the user clicked one of the buttons.
  bool action_taken_;

  // Whether the info-bar should be dismissed on the next navigation.
  bool should_expire_;

  // Used to delay the expiration of the info-bar.
  ScopedRunnableMethodFactory<HintInfoBar> method_factory_;

  DISALLOW_COPY_AND_ASSIGN(HintInfoBar);
};

HintInfoBar::HintInfoBar(OmniboxSearchHint* omnibox_hint)
    : ConfirmInfoBarDelegate(omnibox_hint->tab()->tab_contents()),
      omnibox_hint_(omnibox_hint),
      action_taken_(false),
      should_expire_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  // We want the info-bar to stick-around for few seconds and then be hidden
  // on the next navigation after that.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&HintInfoBar::AllowExpiry),
      8000);  // 8 seconds.
}

HintInfoBar::~HintInfoBar() {
  if (!action_taken_)
    UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Ignored", 1);
}

bool HintInfoBar::ShouldExpire(
    const content::LoadCommittedDetails& details) const {
  return details.is_user_initiated_main_frame_load() && should_expire_;
}

void HintInfoBar::InfoBarDismissed() {
  action_taken_ = true;
  UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Closed", 1);
  // User closed the infobar, let's not bug him again with this in the future.
  omnibox_hint_->DisableHint();
}

gfx::Image* HintInfoBar::GetIcon() const {
  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
     IDR_INFOBAR_QUESTION_MARK);
}

InfoBarDelegate::Type HintInfoBar::GetInfoBarType() const {
  return PAGE_ACTION_TYPE;
}

string16 HintInfoBar::GetMessageText() const {
  return l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT);
}

int HintInfoBar::GetButtons() const {
  return BUTTON_OK;
}

string16 HintInfoBar::GetButtonLabel(InfoBarButton button) const {
  DCHECK_EQ(BUTTON_OK, button);
  return l10n_util::GetStringUTF16(
      IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL);
}

bool HintInfoBar::Accept() {
  action_taken_ = true;
  UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.ShowMe", 1);
  omnibox_hint_->DisableHint();
  omnibox_hint_->ShowEnteringQuery();
  return true;
}

// OmniboxSearchHint ----------------------------------------------------------

OmniboxSearchHint::OmniboxSearchHint(TabContentsWrapper* tab) : tab_(tab) {
  NavigationController* controller = &(tab->controller());
  notification_registrar_.Add(this,
                              NotificationType::NAV_ENTRY_COMMITTED,
                              Source<NavigationController>(controller));
  // Fill the search_engine_urls_ map, used for faster look-up (overkill?).
  for (size_t i = 0;
       i < sizeof(kSearchEngineURLs) / sizeof(kSearchEngineURLs[0]); ++i) {
    search_engine_urls_[kSearchEngineURLs[i]] = 1;
  }

  // Listen for omnibox to figure-out when the user searches from the omnibox.
  notification_registrar_.Add(this,
                              NotificationType::OMNIBOX_OPENED_URL,
                              Source<Profile>(tab->profile()));
}

OmniboxSearchHint::~OmniboxSearchHint() {
}

void OmniboxSearchHint::Observe(NotificationType type,
                                const NotificationSource& source,
                                const NotificationDetails& details) {
  if (type == NotificationType::NAV_ENTRY_COMMITTED) {
    NavigationEntry* entry = tab_->controller().GetActiveEntry();
    if (search_engine_urls_.find(entry->url().spec()) ==
        search_engine_urls_.end()) {
      // The search engine is not in our white-list, bail.
      return;
    }
    const TemplateURL* const default_provider =
        TemplateURLServiceFactory::GetForProfile(tab_->profile())->
        GetDefaultSearchProvider();
    if (!default_provider)
      return;

    const TemplateURLRef* const search_url = default_provider->url();
    if (search_url->GetHost() == entry->url().host())
      ShowInfoBar();
  } else if (type == NotificationType::OMNIBOX_OPENED_URL) {
    AutocompleteLog* log = Details<AutocompleteLog>(details).ptr();
    AutocompleteMatch::Type type =
        log->result.match_at(log->selected_index).type;
    if (type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
        type == AutocompleteMatch::SEARCH_HISTORY ||
        type == AutocompleteMatch::SEARCH_SUGGEST) {
      // The user performed a search from the omnibox, don't show the infobar
      // again.
      DisableHint();
    }
  }
}

void OmniboxSearchHint::ShowInfoBar() {
  tab_->AddInfoBar(new HintInfoBar(this));
}

void OmniboxSearchHint::ShowEnteringQuery() {
  LocationBar* location_bar = BrowserList::GetLastActive()->window()->
      GetLocationBar();
  OmniboxView* omnibox_view = location_bar->location_entry();
  location_bar->FocusLocation(true);
  omnibox_view->SetUserText(
      l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_OMNIBOX_TEXT));
  omnibox_view->SelectAll(false);
  // Entering text in the omnibox view triggers the suggestion popup that we
  // don't want to show in this case.
  omnibox_view->ClosePopup();
}

void OmniboxSearchHint::DisableHint() {
  // The NAV_ENTRY_COMMITTED notification was needed to show the infobar, the
  // OMNIBOX_OPENED_URL notification was there to set the kShowOmniboxSearchHint
  // prefs to false, none of them are needed anymore.
  notification_registrar_.RemoveAll();
  tab_->profile()->GetPrefs()->SetBoolean(prefs::kShowOmniboxSearchHint,
                                          false);
}

// static
bool OmniboxSearchHint::IsEnabled(Profile* profile) {
  // The infobar can only be shown if the correct switch has been provided and
  // the user did not dismiss the infobar before.
  return profile->GetPrefs()->GetBoolean(prefs::kShowOmniboxSearchHint) &&
      CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kSearchInOmniboxHint);
}
<commit_msg>Change BrowserList::GetLastActive to BrowserList::GetLastActiveWithProfile<commit_after>// Copyright (c) 2011 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 "chrome/browser/omnibox_search_hint.h"

#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/task.h"
// TODO(avi): remove when conversions not needed any more
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/browser/tab_contents/navigation_details.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
#include "content/common/notification_type.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources_standard.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"

// The URLs of search engines for which we want to trigger the infobar.
const char* kSearchEngineURLs[] = {
    "http://www.google.com/",
    "http://www.yahoo.com/",
    "http://www.bing.com/",
    "http://www.altavista.com/",
    "http://www.ask.com/",
    "http://www.wolframalpha.com/",
};

// HintInfoBar ----------------------------------------------------------------

class HintInfoBar : public ConfirmInfoBarDelegate {
 public:
  explicit HintInfoBar(OmniboxSearchHint* omnibox_hint);

 private:
  virtual ~HintInfoBar();

  void AllowExpiry() { should_expire_ = true; }

  // ConfirmInfoBarDelegate:
  virtual bool ShouldExpire(
      const content::LoadCommittedDetails& details) const OVERRIDE;
  virtual void InfoBarDismissed() OVERRIDE;
  virtual gfx::Image* GetIcon() const OVERRIDE;
  virtual Type GetInfoBarType() const OVERRIDE;
  virtual string16 GetMessageText() const OVERRIDE;
  virtual int GetButtons() const OVERRIDE;
  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
  virtual bool Accept() OVERRIDE;

  // The omnibox hint that shows us.
  OmniboxSearchHint* omnibox_hint_;

  // Whether the user clicked one of the buttons.
  bool action_taken_;

  // Whether the info-bar should be dismissed on the next navigation.
  bool should_expire_;

  // Used to delay the expiration of the info-bar.
  ScopedRunnableMethodFactory<HintInfoBar> method_factory_;

  DISALLOW_COPY_AND_ASSIGN(HintInfoBar);
};

HintInfoBar::HintInfoBar(OmniboxSearchHint* omnibox_hint)
    : ConfirmInfoBarDelegate(omnibox_hint->tab()->tab_contents()),
      omnibox_hint_(omnibox_hint),
      action_taken_(false),
      should_expire_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  // We want the info-bar to stick-around for few seconds and then be hidden
  // on the next navigation after that.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&HintInfoBar::AllowExpiry),
      8000);  // 8 seconds.
}

HintInfoBar::~HintInfoBar() {
  if (!action_taken_)
    UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Ignored", 1);
}

bool HintInfoBar::ShouldExpire(
    const content::LoadCommittedDetails& details) const {
  return details.is_user_initiated_main_frame_load() && should_expire_;
}

void HintInfoBar::InfoBarDismissed() {
  action_taken_ = true;
  UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Closed", 1);
  // User closed the infobar, let's not bug him again with this in the future.
  omnibox_hint_->DisableHint();
}

gfx::Image* HintInfoBar::GetIcon() const {
  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
     IDR_INFOBAR_QUESTION_MARK);
}

InfoBarDelegate::Type HintInfoBar::GetInfoBarType() const {
  return PAGE_ACTION_TYPE;
}

string16 HintInfoBar::GetMessageText() const {
  return l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT);
}

int HintInfoBar::GetButtons() const {
  return BUTTON_OK;
}

string16 HintInfoBar::GetButtonLabel(InfoBarButton button) const {
  DCHECK_EQ(BUTTON_OK, button);
  return l10n_util::GetStringUTF16(
      IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL);
}

bool HintInfoBar::Accept() {
  action_taken_ = true;
  UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.ShowMe", 1);
  omnibox_hint_->DisableHint();
  omnibox_hint_->ShowEnteringQuery();
  return true;
}

// OmniboxSearchHint ----------------------------------------------------------

OmniboxSearchHint::OmniboxSearchHint(TabContentsWrapper* tab) : tab_(tab) {
  NavigationController* controller = &(tab->controller());
  notification_registrar_.Add(this,
                              NotificationType::NAV_ENTRY_COMMITTED,
                              Source<NavigationController>(controller));
  // Fill the search_engine_urls_ map, used for faster look-up (overkill?).
  for (size_t i = 0;
       i < sizeof(kSearchEngineURLs) / sizeof(kSearchEngineURLs[0]); ++i) {
    search_engine_urls_[kSearchEngineURLs[i]] = 1;
  }

  // Listen for omnibox to figure-out when the user searches from the omnibox.
  notification_registrar_.Add(this,
                              NotificationType::OMNIBOX_OPENED_URL,
                              Source<Profile>(tab->profile()));
}

OmniboxSearchHint::~OmniboxSearchHint() {
}

void OmniboxSearchHint::Observe(NotificationType type,
                                const NotificationSource& source,
                                const NotificationDetails& details) {
  if (type == NotificationType::NAV_ENTRY_COMMITTED) {
    NavigationEntry* entry = tab_->controller().GetActiveEntry();
    if (search_engine_urls_.find(entry->url().spec()) ==
        search_engine_urls_.end()) {
      // The search engine is not in our white-list, bail.
      return;
    }
    const TemplateURL* const default_provider =
        TemplateURLServiceFactory::GetForProfile(tab_->profile())->
        GetDefaultSearchProvider();
    if (!default_provider)
      return;

    const TemplateURLRef* const search_url = default_provider->url();
    if (search_url->GetHost() == entry->url().host())
      ShowInfoBar();
  } else if (type == NotificationType::OMNIBOX_OPENED_URL) {
    AutocompleteLog* log = Details<AutocompleteLog>(details).ptr();
    AutocompleteMatch::Type type =
        log->result.match_at(log->selected_index).type;
    if (type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
        type == AutocompleteMatch::SEARCH_HISTORY ||
        type == AutocompleteMatch::SEARCH_SUGGEST) {
      // The user performed a search from the omnibox, don't show the infobar
      // again.
      DisableHint();
    }
  }
}

void OmniboxSearchHint::ShowInfoBar() {
  tab_->AddInfoBar(new HintInfoBar(this));
}

void OmniboxSearchHint::ShowEnteringQuery() {
  LocationBar* location_bar = BrowserList::GetLastActiveWithProfile(
      tab_->profile())->window()->GetLocationBar();
  OmniboxView* omnibox_view = location_bar->location_entry();
  location_bar->FocusLocation(true);
  omnibox_view->SetUserText(
      l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_OMNIBOX_TEXT));
  omnibox_view->SelectAll(false);
  // Entering text in the omnibox view triggers the suggestion popup that we
  // don't want to show in this case.
  omnibox_view->ClosePopup();
}

void OmniboxSearchHint::DisableHint() {
  // The NAV_ENTRY_COMMITTED notification was needed to show the infobar, the
  // OMNIBOX_OPENED_URL notification was there to set the kShowOmniboxSearchHint
  // prefs to false, none of them are needed anymore.
  notification_registrar_.RemoveAll();
  tab_->profile()->GetPrefs()->SetBoolean(prefs::kShowOmniboxSearchHint,
                                          false);
}

// static
bool OmniboxSearchHint::IsEnabled(Profile* profile) {
  // The infobar can only be shown if the correct switch has been provided and
  // the user did not dismiss the infobar before.
  return profile->GetPrefs()->GetBoolean(prefs::kShowOmniboxSearchHint) &&
      CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kSearchInOmniboxHint);
}
<|endoftext|>


<commit_before><commit_msg>Fix for crash bug in PluginProcessHost::OnGetCookies - it likes like this can be called when we don't have a URLContext from which to return cookies. <commit_after><|endoftext|>