<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 <cctype>
#include <algorithm>

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

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MR", "Miro"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"ST", "SymTorrent"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "uTorrent"}
		, {"XL", "Xunlei"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
		, {"st", "SharkTorrent"}
	};

	struct generic_map_entry
	{
		int offset;
		char const* id;
		char const* name;
	};
	// non-standard names
	generic_map_entry generic_mappings[] =
	{
		{0, "Deadman Walking-", "Deadman"}
		, {5, "Azureus", "Azureus 2.0.3.2"}
		, {0, "DansClient", "XanTorrent"}
		, {4, "btfans", "SimpleBT"}
		, {0, "PRC.P---", "Bittorrent Plus! II"}
		, {0, "P87.P---", "Bittorrent Plus!"}
		, {0, "S587Plus", "Bittorrent Plus!"}
		, {0, "martini", "Martini Man"}
		, {0, "Plus---", "Bittorrent Plus"}
		, {0, "turbobt", "TurboBT"}
		, {0, "a00---0", "Swarmy"}
		, {0, "a02---0", "Swarmy"}
		, {0, "T00---0", "Teeweety"}
		, {0, "BTDWV-", "Deadman Walking"}
		, {2, "BS", "BitSpirit"}
		, {0, "Pando-", "Pando"}
		, {0, "LIME", "LimeWire"}
		, {0, "btuga", "BTugaXP"}
		, {0, "oernu", "BTugaXP"}
		, {0, "Mbrst", "Burst!"}
		, {0, "PEERAPP", "PeerApp"}
		, {0, "Plus", "Plus!"}
		, {0, "-Qt-", "Qt"}
		, {0, "exbc", "BitComet"}
		, {0, "DNA", "BitTorrent DNA"}
		, {0, "-G3", "G3 Torrent"}
		, {0, "-FG", "FlashGet"}
		, {0, "-ML", "MLdonkey"}
		, {0, "XBT", "XBT"}
		, {0, "OP", "Opera"}
		, {2, "RS", "Rufus"}
		, {0, "AZ2500BT", "BitTyrant"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			TORRENT_ASSERT(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);

		for (int i = 0; i < num_generic_mappings; ++i)
		{
			generic_map_entry const& e = generic_mappings[i];
			if (find_string(PID + e.offset, e.id)) return e.name;
		}

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>added LeechCraft to identify client<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 <cctype>
#include <algorithm>

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

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LC", "LeechCraft"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MR", "Miro"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"ST", "SymTorrent"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "uTorrent"}
		, {"XL", "Xunlei"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
		, {"st", "SharkTorrent"}
	};

	struct generic_map_entry
	{
		int offset;
		char const* id;
		char const* name;
	};
	// non-standard names
	generic_map_entry generic_mappings[] =
	{
		{0, "Deadman Walking-", "Deadman"}
		, {5, "Azureus", "Azureus 2.0.3.2"}
		, {0, "DansClient", "XanTorrent"}
		, {4, "btfans", "SimpleBT"}
		, {0, "PRC.P---", "Bittorrent Plus! II"}
		, {0, "P87.P---", "Bittorrent Plus!"}
		, {0, "S587Plus", "Bittorrent Plus!"}
		, {0, "martini", "Martini Man"}
		, {0, "Plus---", "Bittorrent Plus"}
		, {0, "turbobt", "TurboBT"}
		, {0, "a00---0", "Swarmy"}
		, {0, "a02---0", "Swarmy"}
		, {0, "T00---0", "Teeweety"}
		, {0, "BTDWV-", "Deadman Walking"}
		, {2, "BS", "BitSpirit"}
		, {0, "Pando-", "Pando"}
		, {0, "LIME", "LimeWire"}
		, {0, "btuga", "BTugaXP"}
		, {0, "oernu", "BTugaXP"}
		, {0, "Mbrst", "Burst!"}
		, {0, "PEERAPP", "PeerApp"}
		, {0, "Plus", "Plus!"}
		, {0, "-Qt-", "Qt"}
		, {0, "exbc", "BitComet"}
		, {0, "DNA", "BitTorrent DNA"}
		, {0, "-G3", "G3 Torrent"}
		, {0, "-FG", "FlashGet"}
		, {0, "-ML", "MLdonkey"}
		, {0, "XBT", "XBT"}
		, {0, "OP", "Opera"}
		, {2, "RS", "Rufus"}
		, {0, "AZ2500BT", "BitTyrant"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			TORRENT_ASSERT(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);

		for (int i = 0; i < num_generic_mappings; ++i)
		{
			generic_map_entry const& e = generic_mappings[i];
			if (find_string(PID + e.offset, e.id)) return e.name;
		}

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>#pragma once

namespace util{

    void
    validate_probability_vector(const std::vector<float> &p){
        float sum = 0;
        for(auto x: p){
            assert(isfinite(x));
            assert(x >= 0);
            sum+=x;
        }
        assert(std::abs(1 - sum) < 0.01);
    }

    template<typename T> void
    removeFirst(std::vector<T> &v, T element){
        auto it = std::find(v.begin(),v.end(), element);
        if (it != v.end()) {
          v.erase(it);
        }
    }

    // http://stackoverflow.com/a/1267878/982745
    template< class T >
    std::vector<T>
    selectByIndex(const std::vector<T> &v, const std::vector<size_t> &index )  {
        std::vector<T> new_v;
        new_v.reserve(index.size());
        for(size_t i: index){
            new_v.push_back(v[i]);
        }

        return new_v;
    }

    template<class T>
    void
    normalize(std::vector<T> &v){
        for(auto x: v) {
            assert(isfinite(x));
        }
        Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>> vec(v.data(), v.size());
        vec /= vec.sum();
    }

    template<class T, class J>
    class defaultdict{
        J default_value;
        std::map<T, J> map;
    public:
        defaultdict(J val){
            default_value = val;
            map = std::map<T, J>();
        }

        J get(T t) {
            if(map.count(t) > 0){
                return map[t];
            }
            else{
                return default_value;
            }
        }

        void
        set(T t, J j){
            map[t] = j;
        }

        void
        incr(T t, J by){
            if(map.count(t) > 0){
                map[t] += by;
            }
            else{
                map[t] = by + default_value;
            }
        }

        void
        decr(T t, J by){
            if(map.count(t) > 0){
                map[t] -= by;
            }
            else{
                map[t] = default_value - by;
            }
        }

        bool
        contains(T t){
            return map.count(t) > 0;
        }
    };
}<commit_msg>Make global function inline<commit_after>#pragma once

namespace lda_util {

    inline void
    validate_probability_vector(const std::vector<float> &p){
        float sum = 0;
        for(auto x: p){
            assert(isfinite(x));
            assert(x >= 0);
            sum+=x;
        }
        assert(std::abs(1 - sum) < 0.01);
    }

    template<typename T> void
    removeFirst(std::vector<T> &v, T element){
        auto it = std::find(v.begin(),v.end(), element);
        if (it != v.end()) {
          v.erase(it);
        }
    }

    // http://stackoverflow.com/a/1267878/982745
    template< class T >
    std::vector<T>
    selectByIndex(const std::vector<T> &v, const std::vector<size_t> &index )  {
        std::vector<T> new_v;
        new_v.reserve(index.size());
        for(size_t i: index){
            new_v.push_back(v[i]);
        }

        return new_v;
    }

    template<class T>
    void
    normalize(std::vector<T> &v){
        for(auto x: v) {
            assert(isfinite(x));
        }
        Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>> vec(v.data(), v.size());
        vec /= vec.sum();
    }

    template<class T, class J>
    class defaultdict{
        J default_value;
        std::map<T, J> map;
    public:
        defaultdict(J val){
            default_value = val;
            map = std::map<T, J>();
        }

        J get(T t) {
            if(map.count(t) > 0){
                return map[t];
            }
            else{
                return default_value;
            }
        }

        void
        set(T t, J j){
            map[t] = j;
        }

        void
        incr(T t, J by){
            if(map.count(t) > 0){
                map[t] += by;
            }
            else{
                map[t] = by + default_value;
            }
        }

        void
        decr(T t, J by){
            if(map.count(t) > 0){
                map[t] -= by;
            }
            else{
                map[t] = default_value - by;
            }
        }

        bool
        contains(T t){
            return map.count(t) > 0;
        }
    };
}<|endoftext|>


<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 <cctype>
#include <algorithm>

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

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("KT", "KTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("S",  "Shadow")
		, map_entry("SB", "Swiftbit")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("SZ", "Shareaza")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("UT", "MicroTorrent")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
		, map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)")
		, map_entry("pX", "pHoeniX")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_first_string(name_map[i-1]
				, name_map[i].first));
		}
#endif

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>fix for unkown clients using shadow's style<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 <cctype>
#include <algorithm>

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

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("KT", "KTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("S",  "Shadow")
		, map_entry("SB", "Swiftbit")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("SZ", "Shareaza")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("UT", "MicroTorrent")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
		, map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)")
		, map_entry("pX", "pHoeniX")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_first_string(name_map[i-1]
				, name_map[i].first));
		}
#endif

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
		{
			identity << f.id[0];
			if (f.id[1] != 0) identity << f.id[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.id[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/**
 * Created by Jian Chen
 * @since  2016.08.11
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#pragma once

#include "socket/ip/ip_version.hpp"
#include "socket/config.hpp"

namespace chen
{
    class ip_address
    {
    public:
        enum class Type : std::uint8_t
        {
            None = AF_UNSPEC,
            IPv4 = AF_INET,
            IPv6 = AF_INET6
        };

    public:
        /**
         * Construct an null address
         */
        ip_address(std::nullptr_t = nullptr);

        /**
         * Construct an empty address, v4 or v6
         */
        explicit ip_address(Type type);

        /**
         * Construct by version directly
         */
        ip_address(const ip_version4 &v4);
        ip_address(const ip_version6 &v6);

        /**
         * Construct by ip address, accept the following format:
         * For IPv4:
         * :-) ip_address("127.0.0.1")
         * :-) ip_address("127.0.0.1/8")
         * :-) ip_address("127.0.0.1", 8)
         * :-) ip_address("127.0.0.1", "255.0.0.0")
         * :-) ip_address("127")       -> "127.0.0.0"
         * :-) ip_address("127.1")     -> "127.0.0.1"
         * :-) ip_address("192.168.1") -> "192.168.0.1"
         * For IPv6:
         * :-) ip_address("::")
         * :-) ip_address("::1")
         * :-) ip_address("0:0:0:0:0:0:0:1")
         * :-) ip_address("2404:6800:4004:817::200e")
         * :-) ip_address("2404:6800:4004:817:0:0:0:200e")
         * :-) ip_address("2404:6800:4004:817:0000:0000:0000:200e")
         * :-) ip_address("::192.168.0.1")
         * :-) ip_address("2404:6800:4004:817::200e/64")
         * :-) ip_address("2404:6800:4004:817::200e", 64)
         * :-) ip_address("2404:6800:4004:817::200e", "ffff:ffff:ffff:ffff::")
         * :-) ip_address("fe80::1%1")
         * :-) ip_address("fe80::1%lo0")
         * :-) ip_address("fe80::1%1/64")
         * :-) ip_address("fe80::1%lo0/64")
         * :-) ip_address("fe80::1%lo0", 64)
         * :-) ip_address("fe80::1%lo0", "ffff:ffff:ffff:ffff::")
         */
        ip_address(const char *addr);

        ip_address(const std::string &addr);
        ip_address(const std::string &addr, std::uint8_t cidr);
        ip_address(const std::string &addr, std::uint8_t cidr, std::uint32_t scope);
        ip_address(const std::string &addr, const std::string &mask);
        ip_address(const std::string &addr, const std::string &mask, std::uint32_t scope);

    public:
        /**
         * Assignment
         */
        void assign(std::nullptr_t);
        void assign(Type type);

        void assign(const ip_version4 &v4);
        void assign(const ip_version6 &v6);

        void assign(const std::string &addr);
        void assign(const std::string &addr, std::uint8_t cidr);
        void assign(const std::string &addr, std::uint8_t cidr, std::uint32_t scope);
        void assign(const std::string &addr, const std::string &mask);
        void assign(const std::string &addr, const std::string &mask, std::uint32_t scope);

        ip_address& operator=(std::nullptr_t);
        ip_address& operator=(Type type);
        ip_address& operator=(const ip_version4 &v4);
        ip_address& operator=(const ip_version6 &v6);
        ip_address& operator=(const char *addr);
        ip_address& operator=(const std::string &addr);

    public:
        /**
         * Detect type
         */
        Type type() const;

        bool isIPv4() const;
        bool isIPv6() const;

        const ip_version4& v4() const;
        const ip_version6& v6() const;

        ip_version4& v4();
        ip_version6& v6();

    public:
        /**
         * Standard representation, with CIDR or not
         * e.g: 127.0.0.1
         * e.g: 127.0.0.1/8
         * e.g: 2404:6800:4004:817::200e
         * e.g: 2404:6800:4004:817::200e/64
         */
        std::string str(bool cidr = false, bool scope = false) const;

        /**
         * Binary representation
         */
        std::vector<std::uint8_t> bytes() const;

        /**
         * Get raw value
         */
        bool empty() const;
        operator bool() const;

        std::uint8_t cidr() const;
        void cidr(std::uint8_t value);

        std::uint32_t scope() const;
        void scope(std::uint32_t value);

    public:
        /**
         * Network address based on current ip
         */
        ip_address network() const;
        ip_address minhost() const;
        ip_address maxhost() const;

    public:
        /**
         * Special addressing type
         */
        bool isUnspecified() const;
        bool isLoopback() const;
        bool isMulticast() const;

    public:
        /**
         * Operator, consider CIDR and scope
         */
        bool operator==(const ip_address &o) const;
        bool operator!=(const ip_address &o) const;

        bool operator<(const ip_address &o) const;
        bool operator>(const ip_address &o) const;

        bool operator<=(const ip_address &o) const;
        bool operator>=(const ip_address &o) const;

    public:
        /**
         * Common addresses
         */
        static ip_address any(Type type);
        static ip_address loopback(Type type);

    public:
        /**
         * Helper functions
         */
        static Type detect(const std::string &addr);

    private:
        Type _type;

        union
        {
            ip_version4 v4;
            ip_version6 v6;
        } _impl;
    };
}<commit_msg>socket: do not assign platform codes<commit_after>/**
 * Created by Jian Chen
 * @since  2016.08.11
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#pragma once

#include "socket/ip/ip_version.hpp"
#include "socket/config.hpp"

namespace chen
{
    class ip_address
    {
    public:
        enum class Type : std::uint8_t { None, IPv4, IPv6 };

    public:
        /**
         * Construct an null address
         */
        ip_address(std::nullptr_t = nullptr);

        /**
         * Construct an empty address, v4 or v6
         */
        explicit ip_address(Type type);

        /**
         * Construct by version directly
         */
        ip_address(const ip_version4 &v4);
        ip_address(const ip_version6 &v6);

        /**
         * Construct by ip address, accept the following format:
         * For IPv4:
         * :-) ip_address("127.0.0.1")
         * :-) ip_address("127.0.0.1/8")
         * :-) ip_address("127.0.0.1", 8)
         * :-) ip_address("127.0.0.1", "255.0.0.0")
         * :-) ip_address("127")       -> "127.0.0.0"
         * :-) ip_address("127.1")     -> "127.0.0.1"
         * :-) ip_address("192.168.1") -> "192.168.0.1"
         * For IPv6:
         * :-) ip_address("::")
         * :-) ip_address("::1")
         * :-) ip_address("0:0:0:0:0:0:0:1")
         * :-) ip_address("2404:6800:4004:817::200e")
         * :-) ip_address("2404:6800:4004:817:0:0:0:200e")
         * :-) ip_address("2404:6800:4004:817:0000:0000:0000:200e")
         * :-) ip_address("::192.168.0.1")
         * :-) ip_address("2404:6800:4004:817::200e/64")
         * :-) ip_address("2404:6800:4004:817::200e", 64)
         * :-) ip_address("2404:6800:4004:817::200e", "ffff:ffff:ffff:ffff::")
         * :-) ip_address("fe80::1%1")
         * :-) ip_address("fe80::1%lo0")
         * :-) ip_address("fe80::1%1/64")
         * :-) ip_address("fe80::1%lo0/64")
         * :-) ip_address("fe80::1%lo0", 64)
         * :-) ip_address("fe80::1%lo0", "ffff:ffff:ffff:ffff::")
         */
        ip_address(const char *addr);

        ip_address(const std::string &addr);
        ip_address(const std::string &addr, std::uint8_t cidr);
        ip_address(const std::string &addr, std::uint8_t cidr, std::uint32_t scope);
        ip_address(const std::string &addr, const std::string &mask);
        ip_address(const std::string &addr, const std::string &mask, std::uint32_t scope);

    public:
        /**
         * Assignment
         */
        void assign(std::nullptr_t);
        void assign(Type type);

        void assign(const ip_version4 &v4);
        void assign(const ip_version6 &v6);

        void assign(const std::string &addr);
        void assign(const std::string &addr, std::uint8_t cidr);
        void assign(const std::string &addr, std::uint8_t cidr, std::uint32_t scope);
        void assign(const std::string &addr, const std::string &mask);
        void assign(const std::string &addr, const std::string &mask, std::uint32_t scope);

        ip_address& operator=(std::nullptr_t);
        ip_address& operator=(Type type);
        ip_address& operator=(const ip_version4 &v4);
        ip_address& operator=(const ip_version6 &v6);
        ip_address& operator=(const char *addr);
        ip_address& operator=(const std::string &addr);

    public:
        /**
         * Detect type
         */
        Type type() const;

        bool isIPv4() const;
        bool isIPv6() const;

        const ip_version4& v4() const;
        const ip_version6& v6() const;

        ip_version4& v4();
        ip_version6& v6();

    public:
        /**
         * Standard representation, with CIDR or not
         * e.g: 127.0.0.1
         * e.g: 127.0.0.1/8
         * e.g: 2404:6800:4004:817::200e
         * e.g: 2404:6800:4004:817::200e/64
         */
        std::string str(bool cidr = false, bool scope = false) const;

        /**
         * Binary representation
         */
        std::vector<std::uint8_t> bytes() const;

        /**
         * Get raw value
         */
        bool empty() const;
        operator bool() const;

        std::uint8_t cidr() const;
        void cidr(std::uint8_t value);

        std::uint32_t scope() const;
        void scope(std::uint32_t value);

    public:
        /**
         * Network address based on current ip
         */
        ip_address network() const;
        ip_address minhost() const;
        ip_address maxhost() const;

    public:
        /**
         * Special addressing type
         */
        bool isUnspecified() const;
        bool isLoopback() const;
        bool isMulticast() const;

    public:
        /**
         * Operator, consider CIDR and scope
         */
        bool operator==(const ip_address &o) const;
        bool operator!=(const ip_address &o) const;

        bool operator<(const ip_address &o) const;
        bool operator>(const ip_address &o) const;

        bool operator<=(const ip_address &o) const;
        bool operator>=(const ip_address &o) const;

    public:
        /**
         * Common addresses
         */
        static ip_address any(Type type);
        static ip_address loopback(Type type);

    public:
        /**
         * Helper functions
         */
        static Type detect(const std::string &addr);

    private:
        Type _type;

        union
        {
            ip_version4 v4;
            ip_version6 v6;
        } _impl;
    };
}<|endoftext|>


<commit_before><commit_msg>vcl::ITiledRenderable: can mark these methods as pure virtual<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2015, 2016, 2017 LAAS-CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_SRC_IMPLICIT_FUNCTION_HH
# define HPP_CORE_SRC_IMPLICIT_FUNCTION_HH

#include <Eigen/Geometry>
#include <hpp/pinocchio/device.hh>
#include <hpp/pinocchio/liegroup-space.hh>
#include <hpp/constraints/differentiable-function.hh>
#include <hpp/constraints/matrix-view.hh>
#include <hpp/constraints/tools.hh>
#include <hpp/core/explicit-numerical-constraint.hh>

namespace hpp {
  namespace core {

    typedef hpp::pinocchio::liegroup::VectorSpaceOperation <3, false> R3;
    typedef hpp::pinocchio::liegroup::SpecialOrthogonalOperation <3> SO3;
    typedef hpp::pinocchio::liegroup::CartesianProductOperation <R3, SO3>
    R3xSO3;
    typedef se3::SpecialEuclideanOperation <3> SE3;
    typedef hpp::pinocchio::LiegroupType LiegroupType;

    struct JacobianVisitor : public boost::static_visitor <>
    {
      JacobianVisitor (vectorIn_t qOut, vectorIn_t f_qIn,
                       matrixIn_t Jf, const Eigen::MatrixBlocks <false, false>&
                       outJacobian, const Eigen::MatrixBlocks <false, false>&
                       inJacobian, matrixOut_t result) :
        qOut_ (qOut), f_qIn_ (f_qIn), Jf_ (Jf), outJacobian_ (outJacobian),
        inJacobian_ (inJacobian), result_ (result)
      {
      }

      template <typename LgT> void operator () (const LgT&);

      vectorIn_t qOut_, f_qIn_;
      matrixIn_t Jf_;
      const Eigen::MatrixBlocks <false, false>& outJacobian_;
      const Eigen::MatrixBlocks <false, false>& inJacobian_;
      matrixOut_t result_;
    }; // struct JacobianVisitor

    template <> inline void JacobianVisitor::operator () <R3xSO3 >
      (const R3xSO3&)
    {
      using Eigen::MatrixBlocks;
      using Eigen::BlockIndex;
      typedef hpp::constraints::BlockIndex BlockIndex;
      hppDout (info, "result_ = " << std::endl << result_);
      // Fill R^3 part
      assert (outJacobian_.nbRows () == 6);
      Eigen::MatrixBlocks <false, false> tmp (outJacobian_.block (0, 0, 3, 3));
      tmp.lview (result_) = matrix3_t::Identity ();
      hppDout (info, "result_ = " << std::endl << result_);
      // extract 3 top rows of inJacobian_
      segments_t cols (inJacobian_.cols ());
      MatrixBlocks <false, false> inJacobian
        (inJacobian_.block (0, 0, 3, BlockIndex::cardinal (cols)));
      inJacobian.lview (result_) = -Jf_.topRows <3> ();
      hppDout (info, "result_ = " << std::endl << result_);
      // Fill SO(3) part
      // extract 3 bottom rows of inJacobian_
      inJacobian = inJacobian_.block (3, 0, 3, BlockIndex::cardinal (cols));
      // extract 3x3 bottom left part of outJacobian_
      MatrixBlocks <false, false> outJacobian (outJacobian_.block (3, 3, 3, 3));
      assert (qOut_.size () == 7);
      assert (f_qIn_.size () == 7);
      matrix3_t R_out
        (Eigen::Quaterniond (qOut_.tail <4> ()).toRotationMatrix ());
      matrix3_t R_f
        (Eigen::Quaterniond (f_qIn_.tail <4> ()).toRotationMatrix ());
      // \f$R_f^T R_{out}\f$
      matrix3_t R_f_T_R_out (R_f.transpose () * R_out);
      matrix3_t Jlog_R_f_T_R_out;
      vector3_t r;
      value_type theta;
      constraints::logSO3 (R_f_T_R_out, theta, r);
      constraints::JlogSO3 (theta, r, Jlog_R_f_T_R_out);
      outJacobian.lview (result_) = Jlog_R_f_T_R_out;
      hppDout (info, "result_ = " << std::endl << result_);
      inJacobian.lview (result_) = -Jlog_R_f_T_R_out * R_out.transpose () *
        R_f * Jf_.bottomRows <3> ();
      hppDout (info, "result_ = " << std::endl << result_);
    }

    template <> inline void JacobianVisitor::operator () <SE3 > (const SE3&)
    {
      assert (outJacobian_.nbRows () == 6);
      // extract 3 top rows of inJacobian_
      assert (qOut_.size () == 7);
      assert (f_qIn_.size () == 7);
      matrix3_t Rout (Eigen::Quaterniond (qOut_.tail <4> ()).
                      toRotationMatrix ());
      vector3_t pOut (qOut_.head <3> ());
      Transform3f Mout (Rout, pOut);
      matrix3_t Rf (Eigen::Quaterniond (f_qIn_.tail <4> ()).
                    toRotationMatrix ());
      vector3_t pf (f_qIn_.head <3> ());
      Transform3f Mf (Rf, pf);
      // \f$Mf^{-1} M_{out}\f$
      Transform3f Mf_inverse_Mout (Mf.inverse () * Mout);
      matrix6_t Jlog_Mf_inverse_Mout;
      constraints::JlogSE3 (Mf_inverse_Mout, Jlog_Mf_inverse_Mout);
      outJacobian_.lview (result_) = Jlog_Mf_inverse_Mout;
      matrix_t inJ (6, Jf_.cols ());
      inJ.topRows <3> () =
        Rout.transpose () * se3::skew (pOut - pf) * Rf * Jf_.bottomRows <3> ()
        - Rout.transpose () * Rf * Jf_.topRows <3> ();
      inJ.bottomRows <3> () = -Rout.transpose () * Rf * Jf_.bottomRows <3> ();
      inJacobian_.lview (result_) = Jlog_Mf_inverse_Mout * inJ;
    }

    template <typename LgT> void JacobianVisitor::operator () (const LgT&)
    {
      outJacobian_.lview (result_).setIdentity ();
      inJacobian_ .lview (result_) = -Jf_;
    }

    HPP_PREDEF_CLASS (ImplicitFunction);
    typedef boost::shared_ptr <ImplicitFunction> ImplicitFunctionPtr_t;

    /// Function of the form f (q) = q2 - g (q1)
    ///
    /// where
    ///  \li q2 is a vector composed of a subset of configuration variables of
    ///      q,
    ///  \li q1 is the vector composed of the other configuration variables of
    ///      q,
    ///  g is a differentiable function with values in  a Lie group.
    class ImplicitFunction : public DifferentiableFunction
    {
    public:
      static ImplicitFunctionPtr_t create
      (const DevicePtr_t& robot, const DifferentiableFunctionPtr_t& function,
       const segments_t& inputConf, const segments_t& inputVelocity,
       const segments_t& outputConf, const segments_t& outputVelocity)
      {
	ImplicitFunction* ptr = new ImplicitFunction
	  (robot, function, inputConf, inputVelocity, outputConf,
           outputVelocity);
	return ImplicitFunctionPtr_t (ptr);
      }

      /// Get function that maps input variables to output variables
      const DifferentiableFunctionPtr_t& inputToOutput () const
      {
        return inputToOutput_;
      }

    protected:
      ImplicitFunction (const DevicePtr_t& robot,
			const DifferentiableFunctionPtr_t& function,
			const segments_t& inputConf,
			const segments_t& inputVelocity,
                        const segments_t& outputConf,
			const segments_t& outputVelocity)
	: DifferentiableFunction (robot->configSize (), robot->numberDof (),
				  LiegroupSpace::Rn
                                  (function->outputSpace ()->nv ()),
                                  "implicit " + function->name()),
	  robot_ (robot), inputToOutput_ (function),
          inputConfIntervals_ (inputConf),
	  inputDerivIntervals_ (inputVelocity),
          outputConfIntervals_ (outputConf),
	  outputDerivIntervals_ (outputVelocity), outJacobian_ (),
          inJacobian_ (), f_qIn_ (function->outputSpace ()),
          qOut_ (function->outputSpace ()), result_ (outputSpace ())
      {
	// Check input consistency
	// Each configuration variable is either input or output
	assert (function->inputSize () + function->outputSize () <=
		robot->configSize ());
	// Each velocity variable is either input or output
	assert (function->inputDerivativeSize () +
		function->outputDerivativeSize () <= robot->numberDof ());
	qIn_.resize (function->inputSize ());
	Jf_.resize (function->outputDerivativeSize (),
                    function->inputDerivativeSize ());
	assert (BlockIndex::cardinal (outputConf) == function->outputSize ());
	// Sum of velocity output interval sizes equal function output
	// derivative size
	assert (BlockIndex::cardinal (outputVelocity) ==
                function->outputDerivativeSize ());
        computeJacobianBlocks ();

        Eigen::RowBlockIndices (inputConfIntervals_) .lview (activeParameters_.matrix()).setConstant(true);
        Eigen::RowBlockIndices (inputDerivIntervals_).lview (activeDerivativeParameters_.matrix()).setConstant(true);
        Eigen::RowBlockIndices (outputConfIntervals_) .lview (activeParameters_.matrix()).setConstant(true);
        Eigen::RowBlockIndices (outputDerivIntervals_).lview (activeDerivativeParameters_.matrix()).setConstant(true);
      }

      /// Compute q_{output} - f (q_{input})
      void impl_compute (LiegroupElement& result, vectorIn_t argument) const
      {
        using Eigen::MatrixBlocks;
        hppDout (info, "argument=" << argument.transpose ());
        // Store q_{output} in result
        qOut_.vector () = MatrixBlocks <false, true>
          (outputConfIntervals_).rview (argument);
        hppDout (info, "qOut_=" << qOut_);
        // fill in q_{input}
        qIn_ = MatrixBlocks <false, true>
          (inputConfIntervals_).rview (argument);
        hppDout (info, "qIn_=" << qIn_);
        // compute  f (q_{input}) -> output_
	inputToOutput_->value (f_qIn_, qIn_);
        hppDout (info, "f_qIn_=" << f_qIn_);
	result.vector () = qOut_ - f_qIn_;
        hppDout (info, "result=" << result);
      }

      void impl_jacobian (matrixOut_t jacobian, vectorIn_t arg) const
      {
	jacobian.setZero ();
        size_type iq = 0, iv = 0, nq, nv;
        std::size_t rank = 0;
        impl_compute (result_, arg);
        inputToOutput_->jacobian (Jf_, qIn_);
        hppDout (info, "Jf_=" << std::endl << Jf_);
        // Fill Jacobian by set of lines corresponding to the types of Lie group
        // that compose the outputspace of input to output function.
        segments_t outConfSegments (outputConfIntervals_);
        for (std::vector <LiegroupType>::const_iterator it =
               inputToOutput_->outputSpace ()-> liegroupTypes ().begin ();
             it != inputToOutput_->outputSpace ()-> liegroupTypes ().end ();
             ++it) {
          nq = inputToOutput_->outputSpace ()->nq (rank);
          nv = inputToOutput_->outputSpace ()->nv (rank);
          JacobianVisitor v (qOut_.vector ().segment (iq, nq),
                             f_qIn_.vector ().segment (iq, nq),
                             Jf_.middleRows (iv, nv), outJacobian_ [rank],
                             inJacobian_ [rank], jacobian.middleRows (iv, nv));
          boost::apply_visitor (v, *it);
          iq += nq;
          iv += nv;
          ++rank;
        }
      }

    private:
      void computeJacobianBlocks ()
      {
        segments_t remainingCols (outputDerivIntervals_);
        segments_t cols;
        size_type iv = 0, nv;
        std::size_t rank = 0;
        for (std::vector <LiegroupType>::const_iterator it =
               inputToOutput_->outputSpace ()->liegroupTypes ().begin ();
             it != inputToOutput_->outputSpace ()->liegroupTypes ().end ();
             ++it) {
          nv = inputToOutput_->outputSpace ()->nv (rank);
          cols = BlockIndex::split (remainingCols, nv);
          segments_t rows (1, std::make_pair (iv, nv));
          outJacobian_.push_back (Eigen::MatrixBlocks <false, false>
                                  (rows, cols));
          inJacobian_.push_back (Eigen::MatrixBlocks <false, false>
                                 (rows, inputDerivIntervals_));
          //
          iv += nv;
          ++rank;
        }
      }

      DevicePtr_t robot_;
      DifferentiableFunctionPtr_t inputToOutput_;
      segments_t inputConfIntervals_;
      segments_t inputDerivIntervals_;
      segments_t outputConfIntervals_;
      segments_t outputDerivIntervals_;
      std::vector <Eigen::MatrixBlocks <false, false> > outJacobian_;
      std::vector <Eigen::MatrixBlocks <false, false> > inJacobian_;
      mutable vector_t qIn_;
      mutable LiegroupElement f_qIn_, qOut_;
      mutable LiegroupElement result_;
      // Jacobian of explicit function
      mutable matrix_t Jf_;
    }; // class ImplicitFunction

  } // namespace core
} // namespace hpp

#endif // HPP_CORE_SRC_IMPLICIT_FUNCTION_HH
<commit_msg>Improve efficiency of JacobianVisitor<commit_after>// Copyright (c) 2015, 2016, 2017 LAAS-CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_SRC_IMPLICIT_FUNCTION_HH
# define HPP_CORE_SRC_IMPLICIT_FUNCTION_HH

#include <Eigen/Geometry>
#include <hpp/pinocchio/device.hh>
#include <hpp/pinocchio/liegroup-space.hh>
#include <hpp/constraints/differentiable-function.hh>
#include <hpp/constraints/matrix-view.hh>
#include <hpp/constraints/tools.hh>
#include <hpp/core/explicit-numerical-constraint.hh>

namespace hpp {
  namespace core {

    typedef hpp::pinocchio::liegroup::VectorSpaceOperation <3, false> R3;
    typedef hpp::pinocchio::liegroup::SpecialOrthogonalOperation <3> SO3;
    typedef hpp::pinocchio::liegroup::CartesianProductOperation <R3, SO3>
    R3xSO3;
    typedef se3::SpecialEuclideanOperation <3> SE3;
    typedef hpp::pinocchio::LiegroupType LiegroupType;

    struct JacobianVisitor : public boost::static_visitor <>
    {
      JacobianVisitor (vectorIn_t qOut, vectorIn_t f_qIn,
                       matrixIn_t Jf, const Eigen::MatrixBlocks <false, false>&
                       outJacobian, const Eigen::MatrixBlocks <false, false>&
                       inJacobian, matrixOut_t result) :
        qOut_ (qOut), f_qIn_ (f_qIn), Jf_ (Jf), outJacobian_ (outJacobian),
        inJacobian_ (inJacobian), result_ (result)
      {
      }

      template <typename LgT> void operator () (const LgT&);

      vectorIn_t qOut_, f_qIn_;
      matrixIn_t Jf_;
      const Eigen::MatrixBlocks <false, false>& outJacobian_;
      const Eigen::MatrixBlocks <false, false>& inJacobian_;
      matrixOut_t result_;
    }; // struct JacobianVisitor

    template <> inline void JacobianVisitor::operator () <R3xSO3 >
      (const R3xSO3&)
    {
      using Eigen::MatrixBlocks;
      using Eigen::BlockIndex;
      typedef hpp::constraints::BlockIndex BlockIndex;
      hppDout (info, "result_ = " << std::endl << result_);
      // Fill R^3 part
      assert (outJacobian_.nbRows () == 6);
      Eigen::MatrixBlocks <false, false> tmp (outJacobian_.block (0, 0, 3, 3));
      tmp.lview (result_) = matrix3_t::Identity ();
      hppDout (info, "result_ = " << std::endl << result_);
      // extract 3 top rows of inJacobian_
      segments_t cols (inJacobian_.cols ());
      MatrixBlocks <false, false> inJacobian
        (inJacobian_.block (0, 0, 3, BlockIndex::cardinal (cols)));
      inJacobian.lview (result_) = -Jf_.topRows <3> ();
      hppDout (info, "result_ = " << std::endl << result_);
      // Fill SO(3) part
      // extract 3 bottom rows of inJacobian_
      inJacobian = inJacobian_.block (3, 0, 3, BlockIndex::cardinal (cols));
      // extract 3x3 bottom left part of outJacobian_
      MatrixBlocks <false, false> outJacobian (outJacobian_.block (3, 3, 3, 3));
      assert (qOut_.size () == 7);
      assert (f_qIn_.size () == 7);
      matrix3_t R_out
        (Eigen::Quaterniond (qOut_.tail <4> ()).toRotationMatrix ());
      matrix3_t R_f
        (Eigen::Quaterniond (f_qIn_.tail <4> ()).toRotationMatrix ());
      // \f$R_f^T R_{out}\f$
      matrix3_t R_f_T_R_out (R_f.transpose () * R_out);
      matrix3_t Jlog_R_f_T_R_out;
      vector3_t r;
      value_type theta;
      constraints::logSO3 (R_f_T_R_out, theta, r);
      constraints::JlogSO3 (theta, r, Jlog_R_f_T_R_out);
      outJacobian.lview (result_) = Jlog_R_f_T_R_out;
      hppDout (info, "result_ = " << std::endl << result_);
      inJacobian.lview (result_) = -Jlog_R_f_T_R_out * R_out.transpose () *
        R_f * Jf_.bottomRows <3> ();
      hppDout (info, "result_ = " << std::endl << result_);
    }

    template <> inline void JacobianVisitor::operator () <SE3 > (const SE3&)
    {
      assert (outJacobian_.nbRows () == 6);
      // extract 3 top rows of inJacobian_
      assert (qOut_.size () == 7);
      assert (f_qIn_.size () == 7);
      matrix3_t Rout (Eigen::Quaterniond (qOut_.tail <4> ()).
                      toRotationMatrix ());
      vector3_t pOut (qOut_.head <3> ());
      Transform3f Mout (Rout, pOut);
      matrix3_t Rf (Eigen::Quaterniond (f_qIn_.tail <4> ()).
                    toRotationMatrix ());
      vector3_t pf (f_qIn_.head <3> ());
      Transform3f Mf (Rf, pf);
      // \f$Mf^{-1} M_{out}\f$
      Transform3f Mf_inverse_Mout (Mf.inverse () * Mout);
      matrix6_t Jlog_Mf_inverse_Mout;
      constraints::JlogSE3 (Mf_inverse_Mout, Jlog_Mf_inverse_Mout);
      outJacobian_.lview (result_) = Jlog_Mf_inverse_Mout;
      JointJacobian_t inJ (6, Jf_.cols ());
      inJ.topRows <3> ().noalias() =
        (Rout.transpose () * se3::skew (pOut - pf) * Rf ) * Jf_.bottomRows <3> ();
      inJ.topRows <3> ().noalias() -=
        ( Rout.transpose () * Rf ) * Jf_.topRows <3> ();
      inJ.bottomRows <3> ().noalias() = ( - Rout.transpose () * Rf )* Jf_.bottomRows <3> ();
      inJacobian_.lview (result_) = Jlog_Mf_inverse_Mout * inJ;
    }

    template <typename LgT> void JacobianVisitor::operator () (const LgT&)
    {
      outJacobian_.lview (result_).setIdentity ();
      inJacobian_ .lview (result_) = -Jf_;
    }

    HPP_PREDEF_CLASS (ImplicitFunction);
    typedef boost::shared_ptr <ImplicitFunction> ImplicitFunctionPtr_t;

    /// Function of the form f (q) = q2 - g (q1)
    ///
    /// where
    ///  \li q2 is a vector composed of a subset of configuration variables of
    ///      q,
    ///  \li q1 is the vector composed of the other configuration variables of
    ///      q,
    ///  g is a differentiable function with values in  a Lie group.
    class ImplicitFunction : public DifferentiableFunction
    {
    public:
      static ImplicitFunctionPtr_t create
      (const DevicePtr_t& robot, const DifferentiableFunctionPtr_t& function,
       const segments_t& inputConf, const segments_t& inputVelocity,
       const segments_t& outputConf, const segments_t& outputVelocity)
      {
	ImplicitFunction* ptr = new ImplicitFunction
	  (robot, function, inputConf, inputVelocity, outputConf,
           outputVelocity);
	return ImplicitFunctionPtr_t (ptr);
      }

      /// Get function that maps input variables to output variables
      const DifferentiableFunctionPtr_t& inputToOutput () const
      {
        return inputToOutput_;
      }

    protected:
      ImplicitFunction (const DevicePtr_t& robot,
			const DifferentiableFunctionPtr_t& function,
			const segments_t& inputConf,
			const segments_t& inputVelocity,
                        const segments_t& outputConf,
			const segments_t& outputVelocity)
	: DifferentiableFunction (robot->configSize (), robot->numberDof (),
				  LiegroupSpace::Rn
                                  (function->outputSpace ()->nv ()),
                                  "implicit " + function->name()),
	  robot_ (robot), inputToOutput_ (function),
          inputConfIntervals_ (inputConf),
	  inputDerivIntervals_ (inputVelocity),
          outputConfIntervals_ (outputConf),
	  outputDerivIntervals_ (outputVelocity), outJacobian_ (),
          inJacobian_ (), f_qIn_ (function->outputSpace ()),
          qOut_ (function->outputSpace ()), result_ (outputSpace ())
      {
	// Check input consistency
	// Each configuration variable is either input or output
	assert (function->inputSize () + function->outputSize () <=
		robot->configSize ());
	// Each velocity variable is either input or output
	assert (function->inputDerivativeSize () +
		function->outputDerivativeSize () <= robot->numberDof ());
	qIn_.resize (function->inputSize ());
	Jf_.resize (function->outputDerivativeSize (),
                    function->inputDerivativeSize ());
	assert (BlockIndex::cardinal (outputConf) == function->outputSize ());
	// Sum of velocity output interval sizes equal function output
	// derivative size
	assert (BlockIndex::cardinal (outputVelocity) ==
                function->outputDerivativeSize ());
        computeJacobianBlocks ();

        inputConfIntervals_ .lview (activeParameters_.matrix()).setConstant(true);
        inputDerivIntervals_.lview (activeDerivativeParameters_.matrix()).setConstant(true);
        outputConfIntervals_ .lview (activeParameters_.matrix()).setConstant(true);
        outputDerivIntervals_.lview (activeDerivativeParameters_.matrix()).setConstant(true);
      }

      /// Compute q_{output} - f (q_{input})
      void impl_compute (LiegroupElement& result, vectorIn_t argument) const
      {
        using Eigen::MatrixBlocks;
        hppDout (info, "argument=" << argument.transpose ());
        // Store q_{output} in result
        qOut_.vector () = outputConfIntervals_.rview (argument);
        hppDout (info, "qOut_=" << qOut_);
        // fill in q_{input}
        qIn_ = inputConfIntervals_.rview (argument);
        hppDout (info, "qIn_=" << qIn_);
        // compute  f (q_{input}) -> output_
	inputToOutput_->value (f_qIn_, qIn_);
        hppDout (info, "f_qIn_=" << f_qIn_);
	result.vector () = qOut_ - f_qIn_;
        hppDout (info, "result=" << result);
      }

      void impl_jacobian (matrixOut_t jacobian, vectorIn_t arg) const
      {
	jacobian.setZero ();
        size_type iq = 0, iv = 0, nq, nv;
        std::size_t rank = 0;
        impl_compute (result_, arg);
        inputToOutput_->jacobian (Jf_, qIn_);
        hppDout (info, "Jf_=" << std::endl << Jf_);
        // Fill Jacobian by set of lines corresponding to the types of Lie group
        // that compose the outputspace of input to output function.
        for (std::vector <LiegroupType>::const_iterator it =
               inputToOutput_->outputSpace ()-> liegroupTypes ().begin ();
             it != inputToOutput_->outputSpace ()-> liegroupTypes ().end ();
             ++it) {
          nq = inputToOutput_->outputSpace ()->nq (rank);
          nv = inputToOutput_->outputSpace ()->nv (rank);
          JacobianVisitor v (qOut_.vector ().segment (iq, nq),
                             f_qIn_.vector ().segment (iq, nq),
                             Jf_.middleRows (iv, nv), outJacobian_ [rank],
                             inJacobian_ [rank], jacobian.middleRows (iv, nv));
          boost::apply_visitor (v, *it);
          iq += nq;
          iv += nv;
          ++rank;
        }
      }

    private:
      void computeJacobianBlocks ()
      {
        segments_t remainingCols (outputDerivIntervals_.indices());
        segments_t cols;
        size_type iv = 0, nv;
        std::size_t rank = 0;
        for (std::vector <LiegroupType>::const_iterator it =
               inputToOutput_->outputSpace ()->liegroupTypes ().begin ();
             it != inputToOutput_->outputSpace ()->liegroupTypes ().end ();
             ++it) {
          nv = inputToOutput_->outputSpace ()->nv (rank);
          cols = BlockIndex::split (remainingCols, nv);
          segments_t rows (1, std::make_pair (iv, nv));
          outJacobian_.push_back (Eigen::MatrixBlocks <false, false>
                                  (rows, cols));
          inJacobian_.push_back (Eigen::MatrixBlocks <false, false>
                                 (rows, inputDerivIntervals_.indices()));
          //
          iv += nv;
          ++rank;
        }
      }

      DevicePtr_t robot_;
      DifferentiableFunctionPtr_t inputToOutput_;
      Eigen::RowBlockIndices inputConfIntervals_;
      Eigen::RowBlockIndices inputDerivIntervals_;
      Eigen::RowBlockIndices outputConfIntervals_;
      Eigen::RowBlockIndices outputDerivIntervals_;
      std::vector <Eigen::MatrixBlocks <false, false> > outJacobian_;
      std::vector <Eigen::MatrixBlocks <false, false> > inJacobian_;
      mutable vector_t qIn_;
      mutable LiegroupElement f_qIn_, qOut_;
      mutable LiegroupElement result_;
      // Jacobian of explicit function
      mutable matrix_t Jf_;
    }; // class ImplicitFunction

  } // namespace core
} // namespace hpp

#endif // HPP_CORE_SRC_IMPLICIT_FUNCTION_HH
<|endoftext|>