<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.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.id[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.id[0]))
			return boost::optional<fingerprint>();

		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("AX", "BitPump")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CD", "Enhanced CTorrent")
		, map_entry("CT", "CTorrent")
		, map_entry("KT", "KTorrent")
		, map_entry("LP", "lphant")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("R",  "Tribler")
		, 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("TR", "Transmission")
		, 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& lhs, map_entry const& rhs)
	{
		return lhs.first[0] < rhs.first[0]
			|| ((lhs.first[0] == rhs.first[0]) && (lhs.first[1] < rhs.first[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
				, map_entry(f.name, ""), &compare_first_string);

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

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->first))
			identity << i->second;
		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
		// ----------------------

		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>fixed compilation error in previous checkin<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.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);
	}

	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("AX", "BitPump")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CD", "Enhanced CTorrent")
		, map_entry("CT", "CTorrent")
		, map_entry("KT", "KTorrent")
		, map_entry("LP", "lphant")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("R",  "Tribler")
		, 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("TR", "Transmission")
		, 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& lhs, map_entry const& rhs)
	{
		return lhs.first[0] < rhs.first[0]
			|| ((lhs.first[0] == rhs.first[0]) && (lhs.first[1] < rhs.first[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
				, map_entry(f.name, ""), &compare_first_string);

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

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->first))
			identity << i->second;
		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
		// ----------------------

		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>/*

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>

#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"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(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]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| 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()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				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("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	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);

		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, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		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";

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

		// 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 MooPolice client identification<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>

#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"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(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]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| 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()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				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("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		. map_emtry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	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);

		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, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		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";

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

		// 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>/*

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>

#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"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// 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);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		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);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		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)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

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

} // namespace unnamed

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 "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			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();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

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

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

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

			return identity.str();
		}

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

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.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";
		}

		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>*** empty log message ***<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>

#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"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// 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);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		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);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		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)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

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

} // namespace unnamed

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 "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			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();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			else if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

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

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

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

			return identity.str();
		}

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

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.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";
		}

		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>#include <x0/Socket.h>
#include <x0/Buffer.h>
#include <x0/BufferRef.h>
#include <x0/Defines.h>

#if !defined(NDEBUG)
#	include <x0/StackTrace.h>
#endif

#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/sendfile.h>

#include <unistd.h>
#include <system_error>

#define ERROR(msg...) { \
	DEBUG(msg); \
	StackTrace st; \
	DEBUG("Stack Trace:\n%s", st.c_str()); \
}

namespace x0 {

Socket::Socket(struct ev_loop *loop, int fd) :
	loop_(loop),
	fd_(fd),
	watcher_(loop),
	timeout_(0),
	timer_(loop),
	secure_(false),
	state_(OPERATIONAL),
	mode_(IDLE),
	callback_(0),
	callbackData_(0)
{
	watcher_.set<Socket, &Socket::io>(this);
	timer_.set<Socket, &Socket::timeout>(this);
}

Socket::~Socket()
{
	if (fd_ >= 0)
		::close(fd_);
}

bool Socket::setNonBlocking(bool enabled)
{
	if (enabled)
		return fcntl(fd_, F_SETFL, O_NONBLOCK) == 0;
	else
		return fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) & ~O_NONBLOCK) == 0;
}

bool Socket::setTcpNoDelay(bool enable)
{
	int flag = enable ? 1 : 0;
	return setsockopt(fd_, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)) == 0;
}

void Socket::setMode(Mode m)
{
	if (m != mode_)
	{
		//DEBUG("Socket(%d).setMode(%d)", fd_, m);

		static int modes[] = { 0, ev::READ, ev::WRITE };

		watcher_.set(fd_, modes[static_cast<int>(m)]);

		if (mode_ == IDLE)
			watcher_.start();

		mode_ = m;
	}

	if (timeout_ > 0)
		timer_.start(timeout_, 0.0);
}

void Socket::clearReadyCallback()
{
	callback_ = NULL;
	callbackData_ = NULL;
}

void Socket::close()
{
	::close(fd_);
	fd_ = -1;
}

ssize_t Socket::read(Buffer& result)
{
	std::size_t nbytes = result.capacity() - result.size();
	if (nbytes <= 0)
	{
		nbytes = 4096;
		result.reserve(result.size() + nbytes);
	}

	ssize_t rv = ::read(fd_, result.end(), nbytes);
	if (rv > 0)
	{
		auto offset = result.size();
		result.resize(offset + rv);
		//DEBUG("Socket(%d).read(): rv=%ld -> %ld:\n(%s)", fd_, rv, result.size(), result.substr(offset, rv).c_str());
	}
	else if (rv < 0)
	{
		ERROR("Socket(%d).read(): rv=%ld (%s)", fd_, rv, strerror(errno));
	}

//	if (rv < 0)
//		return rv;

	//result.resize(result.size() + rv);

	return rv;
}

ssize_t Socket::write(const BufferRef& source)
{
#if !defined(NDEBUG)
	//DEBUG("Socket(%d).write('%s')", fd_, source.str().c_str());
	int rv = ::write(fd_, source.data(), source.size());

	if (rv < 0)
		ERROR("Socket(%d).write: error (%d): %s", fd_, errno, strerror(errno));

	return rv;
#else
	return ::write(fd_, source.data(), source.size());
#endif
}

ssize_t Socket::write(int fd, off_t *offset, size_t nbytes)
{
#if !defined(NDEBUG)
	//auto offset0 = *offset;
	ssize_t rv = ::sendfile(fd_, fd, offset, nbytes);
	//DEBUG("Socket(%d).write(fd=%d, offset=[%ld->%ld], nbytes=%ld) -> %ld", fd_, fd, offset0, *offset, nbytes, rv);

	if (rv < 0)
		ERROR("Socket(%d).write(): sendfile: rv=%ld (%s)", fd_, rv, strerror(errno));

	return rv;
#else
	return ::sendfile(fd_, fd, offset, nbytes);
#endif
}

void Socket::handshake()
{
	// plain (unencrypted) TCP/IP sockets do not need an additional handshake
}

void Socket::io(ev::io& io, int revents)
{
	//DEBUG("Socket(%d).io(revents=0x%04X): mode=%d", fd_, revents, mode_);
	timer_.stop();

	if (state_ == HANDSHAKE)
		handshake();
	else if (callback_)
		callback_(this, callbackData_);
}

void Socket::timeout(ev::timer& timer, int revents)
{
	//DEBUG("Socket(%d).timeout(revents=0x%04X): mode=%d", fd_, revents, mode_);
	watcher_.stop();

	if (timeoutCallback_)
		timeoutCallback_(this, timeoutData_);
}

} // namespace x0
<commit_msg>[core] Socket: do only debug-log error on real errors (not EINTR/EAGAIN)<commit_after>#include <x0/Socket.h>
#include <x0/Buffer.h>
#include <x0/BufferRef.h>
#include <x0/Defines.h>

#if !defined(NDEBUG)
#	include <x0/StackTrace.h>
#endif

#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/sendfile.h>

#include <unistd.h>
#include <system_error>

#define ERROR(msg...) { \
	DEBUG(msg); \
	StackTrace st; \
	DEBUG("Stack Trace:\n%s", st.c_str()); \
}

namespace x0 {

Socket::Socket(struct ev_loop *loop, int fd) :
	loop_(loop),
	fd_(fd),
	watcher_(loop),
	timeout_(0),
	timer_(loop),
	secure_(false),
	state_(OPERATIONAL),
	mode_(IDLE),
	callback_(0),
	callbackData_(0)
{
	watcher_.set<Socket, &Socket::io>(this);
	timer_.set<Socket, &Socket::timeout>(this);
}

Socket::~Socket()
{
	if (fd_ >= 0)
		::close(fd_);
}

bool Socket::setNonBlocking(bool enabled)
{
	if (enabled)
		return fcntl(fd_, F_SETFL, O_NONBLOCK) == 0;
	else
		return fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) & ~O_NONBLOCK) == 0;
}

bool Socket::setTcpNoDelay(bool enable)
{
	int flag = enable ? 1 : 0;
	return setsockopt(fd_, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)) == 0;
}

void Socket::setMode(Mode m)
{
	if (m != mode_)
	{
		//DEBUG("Socket(%d).setMode(%d)", fd_, m);

		static int modes[] = { 0, ev::READ, ev::WRITE };

		watcher_.set(fd_, modes[static_cast<int>(m)]);

		if (mode_ == IDLE)
			watcher_.start();

		mode_ = m;
	}

	if (timeout_ > 0)
		timer_.start(timeout_, 0.0);
}

void Socket::clearReadyCallback()
{
	callback_ = NULL;
	callbackData_ = NULL;
}

void Socket::close()
{
	::close(fd_);
	fd_ = -1;
}

ssize_t Socket::read(Buffer& result)
{
	std::size_t nbytes = result.capacity() - result.size();
	if (nbytes <= 0)
	{
		nbytes = 4096;
		result.reserve(result.size() + nbytes);
	}

	ssize_t rv = ::read(fd_, result.end(), nbytes);
	if (rv > 0)
	{
		auto offset = result.size();
		result.resize(offset + rv);
		//DEBUG("Socket(%d).read(): rv=%ld -> %ld:\n(%s)", fd_, rv, result.size(), result.substr(offset, rv).c_str());
	}
	else if (rv < 0 && errno != EINTR && errno != EAGAIN)
	{
		ERROR("Socket(%d).read(): rv=%ld (%s)", fd_, rv, strerror(errno));
	}

//	if (rv < 0)
//		return rv;

	//result.resize(result.size() + rv);

	return rv;
}

ssize_t Socket::write(const BufferRef& source)
{
#if !defined(NDEBUG)
	//DEBUG("Socket(%d).write('%s')", fd_, source.str().c_str());
	int rv = ::write(fd_, source.data(), source.size());

	if (rv < 0 && errno != EINTR && errno != EAGAIN)
		ERROR("Socket(%d).write: error (%d): %s", fd_, errno, strerror(errno));

	return rv;
#else
	return ::write(fd_, source.data(), source.size());
#endif
}

ssize_t Socket::write(int fd, off_t *offset, size_t nbytes)
{
#if !defined(NDEBUG)
	//auto offset0 = *offset;
	ssize_t rv = ::sendfile(fd_, fd, offset, nbytes);
	//DEBUG("Socket(%d).write(fd=%d, offset=[%ld->%ld], nbytes=%ld) -> %ld", fd_, fd, offset0, *offset, nbytes, rv);

	if (rv < 0 && errno != EINTR && errno != EAGAIN)
		ERROR("Socket(%d).write(): sendfile: rv=%ld (%s)", fd_, rv, strerror(errno));

	return rv;
#else
	return ::sendfile(fd_, fd, offset, nbytes);
#endif
}

void Socket::handshake()
{
	// plain (unencrypted) TCP/IP sockets do not need an additional handshake
}

void Socket::io(ev::io& io, int revents)
{
	//DEBUG("Socket(%d).io(revents=0x%04X): mode=%d", fd_, revents, mode_);
	timer_.stop();

	if (state_ == HANDSHAKE)
		handshake();
	else if (callback_)
		callback_(this, callbackData_);
}

void Socket::timeout(ev::timer& timer, int revents)
{
	//DEBUG("Socket(%d).timeout(revents=0x%04X): mode=%d", fd_, revents, mode_);
	watcher_.stop();

	if (timeoutCallback_)
		timeoutCallback_(this, timeoutData_);
}

} // namespace x0
<|endoftext|>


<commit_before>#include "Scene.h"

#include <fstream>
#include <string>
#include <list>

#include "scene_parser.h"

#include <GL\glew.h>
#include <algorithm>

#include <boost/filesystem.hpp>

//Ci serve per indicare la directory del file che stiamo parsando
//cos da poter leggere scene anche se non sono nella cartella dell'eseguibile
std::string extractDirectory(const std::string& path )
{
	return path.substr( 0, path.find_last_of( '\\' ) +1 );
}

//Caricamento della scena da file
Scene* Scene::load(string fileName)
{
	int lightCount = 0;
	Scene *scene = new Scene();
	boost::filesystem::path scenePath = boost::filesystem::path(fileName).parent_path();
	ifstream fstream(fileName.c_str());

	if(fstream.good())
	{
		while(!fstream.eof())
		{
			string key = getKeyword(fstream);

			if(key.compare("Camera") == 0) //trovata una camera
			{
				Camera camera = parseCamera(fstream, scenePath);
				camera.initCamera();
				if(camera.make_resources() == 0)
				{
					throw ParseException(FILE_MISSING);
				}
				scene->addCamera(camera);
			}
			else if(key.compare("Transform") == 0) //trovata una trasformazione affine
			{
				Transform transform = parseTransform(fstream, scenePath, lightCount);
				scene->rootTransform.addChild(transform);
			}
			else if(key.compare("#") == 0) //commento, va ignorato
				skipComment(fstream);
			else
				throw ParseException(WRONG_SYNTAX);
		}

	}
	else
		throw ParseException(CANT_OPEN_FILE);

	return scene;
}

Scene::Scene()
{
	cameras = std::vector<Camera>();
	//Valore con cui accediamo al vettore delle camere per ottenere quella attiva.
	activeCamera = 0;
}

void Scene::addCamera(Camera camera)
{
	cameras.push_back(camera);
}

void Scene::previsitLights()
{
	glEnable(GL_LIGHTING);
	rootTransform.previsitLights();
}

void Scene::render()
{
	//Implementazione dell'algoritmo 2 per le superfici semitrasparenti.
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDepthMask(GL_TRUE);
	rootTransform.render(false);
}

//Vai alla camera precedente
void Scene::prevCamera()
{
	if(activeCamera == 0)
	{
		//Cicliamo le telecamere
		activeCamera = cameras.size() - 1;
	}
	else
	{
		activeCamera--;
	}
	glutPostRedisplay();
}

//Vai alla camera successiva
void Scene::nextCamera()
{
	if(activeCamera == cameras.size() - 1)
	{
		//Cicliamo le telecamere
		activeCamera = 0;
	}
	else
	{
		activeCamera++;
	}
	glutPostRedisplay();
}

//Ottiene un riferimento alla camera attuale.
//Se venisse passata per copia non si vedrebbero
//Modifiche quando si sposta la telecamera
Camera& Scene::getActiveCamera()
{
	return cameras[activeCamera];
}
<commit_msg>Fixes for last commit breaking opening files.<commit_after>#include "Scene.h"

#include <fstream>
#include <string>
#include <list>

#include "scene_parser.h"

#include <GL\glew.h>
#include <algorithm>

#include <boost/filesystem.hpp>

//Ci serve per indicare la directory del file che stiamo parsando
//cos da poter leggere scene anche se non sono nella cartella dell'eseguibile
std::string extractDirectory(const std::string& path )
{
	return path.substr( 0, path.find_last_of( '\\' ) +1 );
}

//Caricamento della scena da file
Scene* Scene::load(string fileName)
{
	int lightCount = 0;
	Scene *scene = new Scene();
	boost::filesystem::path scenePath = boost::filesystem::current_path();
	boost::filesystem::path filePath = scenePath / boost::filesystem::path(fileName);
	fileName = filePath.string();
	ifstream fstream(fileName.c_str());

	if(fstream.good())
	{
		while(!fstream.eof())
		{
			string key = getKeyword(fstream);

			if(key.compare("Camera") == 0) //trovata una camera
			{
				Camera camera = parseCamera(fstream, scenePath);
				camera.initCamera();
				if(camera.make_resources() == 0)
				{
					throw ParseException(FILE_MISSING);
				}
				scene->addCamera(camera);
			}
			else if(key.compare("Transform") == 0) //trovata una trasformazione affine
			{
				Transform transform = parseTransform(fstream, scenePath, lightCount);
				scene->rootTransform.addChild(transform);
			}
			else if(key.compare("#") == 0) //commento, va ignorato
				skipComment(fstream);
			else
				throw ParseException(WRONG_SYNTAX);
		}

	}
	else
		throw ParseException(CANT_OPEN_FILE);

	return scene;
}

Scene::Scene()
{
	cameras = std::vector<Camera>();
	//Valore con cui accediamo al vettore delle camere per ottenere quella attiva.
	activeCamera = 0;
}

void Scene::addCamera(Camera camera)
{
	cameras.push_back(camera);
}

void Scene::previsitLights()
{
	glEnable(GL_LIGHTING);
	rootTransform.previsitLights();
}

void Scene::render()
{
	//Implementazione dell'algoritmo 2 per le superfici semitrasparenti.
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDepthMask(GL_TRUE);
	rootTransform.render(false);
}

//Vai alla camera precedente
void Scene::prevCamera()
{
	if(activeCamera == 0)
	{
		//Cicliamo le telecamere
		activeCamera = cameras.size() - 1;
	}
	else
	{
		activeCamera--;
	}
	glutPostRedisplay();
}

//Vai alla camera successiva
void Scene::nextCamera()
{
	if(activeCamera == cameras.size() - 1)
	{
		//Cicliamo le telecamere
		activeCamera = 0;
	}
	else
	{
		activeCamera++;
	}
	glutPostRedisplay();
}

//Ottiene un riferimento alla camera attuale.
//Se venisse passata per copia non si vedrebbero
//Modifiche quando si sposta la telecamera
Camera& Scene::getActiveCamera()
{
	return cameras[activeCamera];
}
<|endoftext|>


<commit_before><commit_msg>add push_status operation constant<commit_after><|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////

// This include needs to be the very first to prevent problems with warnings
// regarding redefinition of _POSIX_C_SOURCE
#include <boost/python.hpp>

// System includes
#include <string>
#include <stdexcept>

#include <OpenEXR/ImathEuler.h>

#include "IECore/bindings/ImathVecBinding.h"
#include "IECore/bindings/IECoreBinding.h"

using namespace boost::python;
using namespace Imath;
using namespace std;

namespace IECore
{

template<typename T>
void bindEuler(const char *bindName);

void bindImathEuler()
{
	bindEuler<float>("Eulerf");
	bindEuler<double>("Eulerd");
}

#define DEFINEEULERSTRSPECIALISATION( EULER )\
\
template<>\
std::string repr<EULER>( EULER &x )\
{\
	std::stringstream s;\
	s << #EULER << "( ";\
	for( unsigned i=0; i<EULER::dimensions(); i++ )\
	{\
		s << x[i];\
		if( i!=EULER::dimensions()-1 )\
		{\
			s << ", ";\
		}\
	}\
	s << " )";\
	return s.str();\
}\
\
template<>\
std::string str<EULER>( EULER &x )\
{\
	std::stringstream s;\
	for( unsigned i=0; i<EULER::dimensions(); i++ )\
	{\
		s << x[i];\
		if( i!=EULER::dimensions()-1 )\
		{\
			s << " ";\
		}\
	}\
	return s.str();\
}\

DEFINEEULERSTRSPECIALISATION( Eulerf );
DEFINEEULERSTRSPECIALISATION( Eulerd );

template<typename T>
struct EulerHelper
{
	typedef typename Euler<T>::Order OrderType;

	static tuple angleOrder( Euler<T> &e )
	{
		int i, j, k;
		e.angleOrder( i, j, k );

		return make_tuple( i, j, k );
	}

	static tuple angleMapping( Euler<T> &e )
	{
		int i, j, k;
		e.angleMapping( i, j, k );

		return make_tuple( i, j, k );
	}

	Vec3<T> simpleXYZRotation( Vec3<T> &xyzRot, const Vec3<T> targetXyzRot )
	{
		Euler<T>::simpleXYZRotation( xyzRot, targetXyzRot );

		return xyzRot;
	}

	Vec3<T> nearestRotation( Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot, OrderType order )
	{
		Euler<T>::nearestRotation( xyzRot, targetXyzRot, order );

		return xyzRot;
	}

	Vec3<T> nearestRotation( Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot )
	{
		return nearestRotation( xyzRot, targetXyzRot, (OrderType)(Euler<T>::XYZ) );
	}
};

template<typename T>
void bindEuler(const char *bindName)
{
	/// We need these typedefs so we can instantiate the "optional" and "enum_" templates.
	// Without them, the enums defined in Imath::Euler aren't types.
	typedef typename Euler<T>::Order OrderType;
	typedef typename Euler<T>::InputLayout InputLayoutType;
	typedef typename Euler<T>::Axis AxisType;

	void (Euler<T>::*extractM33)(const Matrix33<T>&) = &Euler<T>::extract;
	void (Euler<T>::*extractM44)(const Matrix44<T>&) = &Euler<T>::extract;
	void (Euler<T>::*extractQuat)(const Quat<T>&) = &Euler<T>::extract;

	Vec3<T> (EulerHelper<T>::*nearestRotation1)( Vec3<T> &, const Vec3<T> &, OrderType )= &EulerHelper<T>::nearestRotation;
	Vec3<T> (EulerHelper<T>::*nearestRotation2)( Vec3<T> &, const Vec3<T> & )= &EulerHelper<T>::nearestRotation;

	object euler = class_< Euler<T>, bases< Vec3<T> > >(bindName)

		.def( init<>() )
		.def( init< const Euler<T> & >() )
		.def( init< OrderType >() )
		.def( init< const Vec3<T> &, optional< OrderType, InputLayoutType > >() )
		.def( init< T, T, T, optional< OrderType, InputLayoutType > >() )
		.def( init< const Euler<T> &, optional< OrderType > >() )
		.def( init< const Matrix33<T> &, optional< OrderType > > () )
		.def( init< const Matrix44<T> &, optional< OrderType > > () )

		.def( "__str__", &IECore::str<Euler<T> > )
		.def( "__repr__", &IECore::repr<Euler<T> > )

		.def( "legal", &Euler<T>::legal ).staticmethod("legal")

		.def( "setXYZVector", &Euler<T>::setXYZVector )

		.def( "order", &Euler<T>::order )
		.def( "setOrder", &Euler<T>::setOrder )

		.def( "set", &Euler<T>::set )

		.def( "extract", extractM33 )
		.def( "extract", extractM44 )
		.def( "extract", extractQuat )

		.def( "toMatrix33", &Euler<T>::toMatrix33 )
		.def( "toMatrix44", &Euler<T>::toMatrix44 )
		.def( "toQuat", &Euler<T>::toQuat )
		.def( "toXYZVector", &Euler<T>::toXYZVector )

		.def( "angleOrder", &EulerHelper<T>::angleOrder )
		.def( "angleMapping", &EulerHelper<T>::angleOrder )

		.def( "angleMod", &Euler<T>::angleMod ).staticmethod("angleMod")
		.def( "simpleXYZRotation", &EulerHelper<T>::simpleXYZRotation ).staticmethod("simpleXYZRotation")
		.def( "nearestRotation", nearestRotation1 ).staticmethod("nearestRotation")
		.def( "nearestRotation", nearestRotation2 ).staticmethod("nearestRotation")

		.def( "makeNear", &Euler<T>::makeNear )

		.def( "frameStatic", &Euler<T>::frameStatic )
		.def( "initialRepeated", &Euler<T>::initialRepeated )
		.def( "parityEven", &Euler<T>::parityEven )
		.def( "initialAxis", &Euler<T>::initialAxis )
	;

	scope eulerScope (euler );

	enum_< OrderType >( "Order" )
		.value( "XYZ", Euler<T>::XYZ )
		.value( "XZY", Euler<T>::XZY )
		.value( "YZX", Euler<T>::YZX )
		.value( "YXZ", Euler<T>::YXZ )
		.value( "ZXY", Euler<T>::ZXY )
		.value( "ZYX", Euler<T>::ZYX )

		.value( "XZX", Euler<T>::XZX )
		.value( "XYX", Euler<T>::XYX )
		.value( "YXY", Euler<T>::YXY )
		.value( "YZY", Euler<T>::YZY )
		.value( "ZYZ", Euler<T>::ZYZ )
		.value( "ZXZ", Euler<T>::ZXZ )

		.value( "XYZr", Euler<T>::XYZr )
		.value( "XZYr", Euler<T>::XZYr )
		.value( "YZXr", Euler<T>::YZXr )
		.value( "YXZr", Euler<T>::YXZr )
		.value( "ZXYr", Euler<T>::ZXYr )
		.value( "ZYXr", Euler<T>::ZYXr )

		.value( "XZXr", Euler<T>::XZXr )
		.value( "XYXr", Euler<T>::XYXr )
		.value( "YXYr", Euler<T>::YXYr )
		.value( "YZYr", Euler<T>::YZYr )
		.value( "ZYZr", Euler<T>::ZYZr )
		.value( "ZXZr", Euler<T>::ZXZr )

		.value( "Default", Euler<T>::Default )
	;

	enum_< InputLayoutType >( "InputLayout" )
		.value( "XYZLayout", Euler<T>::XYZLayout )
		.value( "IJKLayout", Euler<T>::IJKLayout )
	;

	enum_< AxisType >( "Axis" )
		.value( "X", Euler<T>::X )
		.value( "Y", Euler<T>::Y )
		.value( "Z", Euler<T>::Z )
	;
}

}
<commit_msg>Really fixed nearestRotation binding<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////

// This include needs to be the very first to prevent problems with warnings
// regarding redefinition of _POSIX_C_SOURCE
#include <boost/python.hpp>

// System includes
#include <string>
#include <stdexcept>

#include <OpenEXR/ImathEuler.h>

#include "IECore/bindings/ImathVecBinding.h"
#include "IECore/bindings/IECoreBinding.h"

using namespace boost::python;
using namespace Imath;
using namespace std;

namespace IECore
{

template<typename T>
void bindEuler(const char *bindName);

void bindImathEuler()
{
	bindEuler<float>("Eulerf");
	bindEuler<double>("Eulerd");
}

#define DEFINEEULERSTRSPECIALISATION( EULER )\
\
template<>\
std::string repr<EULER>( EULER &x )\
{\
	std::stringstream s;\
	s << #EULER << "( ";\
	for( unsigned i=0; i<EULER::dimensions(); i++ )\
	{\
		s << x[i];\
		if( i!=EULER::dimensions()-1 )\
		{\
			s << ", ";\
		}\
	}\
	s << " )";\
	return s.str();\
}\
\
template<>\
std::string str<EULER>( EULER &x )\
{\
	std::stringstream s;\
	for( unsigned i=0; i<EULER::dimensions(); i++ )\
	{\
		s << x[i];\
		if( i!=EULER::dimensions()-1 )\
		{\
			s << " ";\
		}\
	}\
	return s.str();\
}\

DEFINEEULERSTRSPECIALISATION( Eulerf );
DEFINEEULERSTRSPECIALISATION( Eulerd );

template<typename T>
struct EulerHelper
{
	typedef typename Euler<T>::Order OrderType;

	static tuple angleOrder( Euler<T> &e )
	{
		int i, j, k;
		e.angleOrder( i, j, k );

		return make_tuple( i, j, k );
	}

	static tuple angleMapping( Euler<T> &e )
	{
		int i, j, k;
		e.angleMapping( i, j, k );

		return make_tuple( i, j, k );
	}

	static Vec3<T> simpleXYZRotation( Vec3<T> &xyzRot, const Vec3<T> targetXyzRot )
	{
		Euler<T>::simpleXYZRotation( xyzRot, targetXyzRot );

		return xyzRot;
	}

	static Vec3<T> nearestRotation( Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot, OrderType order )
	{
		Euler<T>::nearestRotation( xyzRot, targetXyzRot, order );

		return xyzRot;
	}

	static Vec3<T> nearestRotation( Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot )
	{
		return nearestRotation( xyzRot, targetXyzRot, (OrderType)(Euler<T>::XYZ) );
	}
};

template<typename T>
void bindEuler(const char *bindName)
{
	/// We need these typedefs so we can instantiate the "optional" and "enum_" templates.
	// Without them, the enums defined in Imath::Euler aren't types.
	typedef typename Euler<T>::Order OrderType;
	typedef typename Euler<T>::InputLayout InputLayoutType;
	typedef typename Euler<T>::Axis AxisType;

	void (Euler<T>::*extractM33)(const Matrix33<T>&) = &Euler<T>::extract;
	void (Euler<T>::*extractM44)(const Matrix44<T>&) = &Euler<T>::extract;
	void (Euler<T>::*extractQuat)(const Quat<T>&) = &Euler<T>::extract;

	Vec3<T> (*nearestRotation1)( Vec3<T> &, const Vec3<T> &, OrderType )= &EulerHelper<T>::nearestRotation;
	Vec3<T> (*nearestRotation2)( Vec3<T> &, const Vec3<T> & )= &EulerHelper<T>::nearestRotation;

	object euler = class_< Euler<T>, bases< Vec3<T> > >(bindName)

		.def( init<>() )
		.def( init< const Euler<T> & >() )
		.def( init< OrderType >() )
		.def( init< const Vec3<T> &, optional< OrderType, InputLayoutType > >() )
		.def( init< T, T, T, optional< OrderType, InputLayoutType > >() )
		.def( init< const Euler<T> &, optional< OrderType > >() )
		.def( init< const Matrix33<T> &, optional< OrderType > > () )
		.def( init< const Matrix44<T> &, optional< OrderType > > () )

		.def( "__str__", &IECore::str<Euler<T> > )
		.def( "__repr__", &IECore::repr<Euler<T> > )

		.def( "legal", &Euler<T>::legal ).staticmethod("legal")

		.def( "setXYZVector", &Euler<T>::setXYZVector )

		.def( "order", &Euler<T>::order )
		.def( "setOrder", &Euler<T>::setOrder )

		.def( "set", &Euler<T>::set )

		.def( "extract", extractM33 )
		.def( "extract", extractM44 )
		.def( "extract", extractQuat )

		.def( "toMatrix33", &Euler<T>::toMatrix33 )
		.def( "toMatrix44", &Euler<T>::toMatrix44 )
		.def( "toQuat", &Euler<T>::toQuat )
		.def( "toXYZVector", &Euler<T>::toXYZVector )

		.def( "angleOrder", &EulerHelper<T>::angleOrder )
		.def( "angleMapping", &EulerHelper<T>::angleOrder )

		.def( "angleMod", &Euler<T>::angleMod ).staticmethod("angleMod")
		.def( "simpleXYZRotation", &EulerHelper<T>::simpleXYZRotation ).staticmethod("simpleXYZRotation")
		.def( "nearestRotation", nearestRotation1 )
		.def( "nearestRotation", nearestRotation2 ).staticmethod("nearestRotation")

		.def( "makeNear", &Euler<T>::makeNear )

		.def( "frameStatic", &Euler<T>::frameStatic )
		.def( "initialRepeated", &Euler<T>::initialRepeated )
		.def( "parityEven", &Euler<T>::parityEven )
		.def( "initialAxis", &Euler<T>::initialAxis )
	;

	scope eulerScope (euler );

	enum_< OrderType >( "Order" )
		.value( "XYZ", Euler<T>::XYZ )
		.value( "XZY", Euler<T>::XZY )
		.value( "YZX", Euler<T>::YZX )
		.value( "YXZ", Euler<T>::YXZ )
		.value( "ZXY", Euler<T>::ZXY )
		.value( "ZYX", Euler<T>::ZYX )

		.value( "XZX", Euler<T>::XZX )
		.value( "XYX", Euler<T>::XYX )
		.value( "YXY", Euler<T>::YXY )
		.value( "YZY", Euler<T>::YZY )
		.value( "ZYZ", Euler<T>::ZYZ )
		.value( "ZXZ", Euler<T>::ZXZ )

		.value( "XYZr", Euler<T>::XYZr )
		.value( "XZYr", Euler<T>::XZYr )
		.value( "YZXr", Euler<T>::YZXr )
		.value( "YXZr", Euler<T>::YXZr )
		.value( "ZXYr", Euler<T>::ZXYr )
		.value( "ZYXr", Euler<T>::ZYXr )

		.value( "XZXr", Euler<T>::XZXr )
		.value( "XYXr", Euler<T>::XYXr )
		.value( "YXYr", Euler<T>::YXYr )
		.value( "YZYr", Euler<T>::YZYr )
		.value( "ZYZr", Euler<T>::ZYZr )
		.value( "ZXZr", Euler<T>::ZXZr )

		.value( "Default", Euler<T>::Default )
	;

	enum_< InputLayoutType >( "InputLayout" )
		.value( "XYZLayout", Euler<T>::XYZLayout )
		.value( "IJKLayout", Euler<T>::IJKLayout )
	;

	enum_< AxisType >( "Axis" )
		.value( "X", Euler<T>::X )
		.value( "Y", Euler<T>::Y )
		.value( "Z", Euler<T>::Z )
	;
}

}
<|endoftext|>


<commit_before><commit_msg>RPC, cosmetic: push down ReadHTTPStatus() calls into ReadHTTP() callers<commit_after><|endoftext|>


<commit_before><commit_msg>Code refactor to aid development<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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/external_protocol_handler.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#endif

#include <set>

#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"

#if defined(OS_WIN)
#include "base/registry.h"
#include "chrome/browser/views/external_protocol_dialog.h"
#elif defined(OS_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#endif

// static
void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) {
  static bool is_warm = false;
  if (is_warm)
    return;
  is_warm = true;

  static const wchar_t* const denied_schemes[] = {
    L"afp",
    L"data",
    L"disk",
    L"disks",
    // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply
    // execute the file specified!  Hopefully we won't see any "file" schemes
    // because we think of file:// URLs as handled URLs, but better to be safe
    // than to let an attacker format the user's hard drive.
    L"file",
    L"hcp",
    L"javascript",
    L"ms-help",
    L"nntp",
    L"shell",
    L"vbscript",
    // view-source is a special case in chrome. When it comes through an
    // iframe or a redirect, it looks like an external protocol, but we don't
    // want to shellexecute it.
    L"view-source",
    L"vnd.ms.radio",
  };

  static const wchar_t* const allowed_schemes[] = {
    L"mailto",
    L"news",
    L"snews",
  };

  bool should_block;
  for (size_t i = 0; i < arraysize(denied_schemes); ++i) {
    if (!win_pref->GetBoolean(denied_schemes[i], &should_block)) {
      win_pref->SetBoolean(denied_schemes[i], true);
    }
  }

  for (size_t i = 0; i < arraysize(allowed_schemes); ++i) {
    if (!win_pref->GetBoolean(allowed_schemes[i], &should_block)) {
      win_pref->SetBoolean(allowed_schemes[i], false);
    }
  }
}

// static
ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState(
    const std::wstring& scheme) {
  if (scheme.length() == 1) {
    // We have a URL that looks something like:
    //   C:/WINDOWS/system32/notepad.exe
    // ShellExecuting this URL will cause the specified program to be executed.
    return BLOCK;
  }

  // Check the stored prefs.
  // TODO(pkasting): http://b/119651 This kind of thing should go in the
  // preferences on the profile, not in the local state.
  PrefService* pref = g_browser_process->local_state();
  if (pref) {  // May be NULL during testing.
    DictionaryValue* win_pref =
        pref->GetMutableDictionary(prefs::kExcludedSchemes);
    CHECK(win_pref);

    // Warm up the dictionary if needed.
    PrepopulateDictionary(win_pref);

    bool should_block;
    if (win_pref->GetBoolean(scheme, &should_block))
      return should_block ? BLOCK : DONT_BLOCK;
  }

  return UNKNOWN;
}

// static
void ExternalProtocolHandler::LaunchUrl(const GURL& url,
                                        int render_process_host_id,
                                        int tab_contents_id) {
#if !defined(OS_LINUX)
  // Escape the input scheme to be sure that the command does not
  // have parameters unexpected by the external program.
  std::string escaped_url_string = EscapeExternalHandlerValue(url.spec());
  GURL escaped_url(escaped_url_string);
  BlockState block_state = GetBlockState(ASCIIToWide(escaped_url.scheme()));
  if (block_state == BLOCK)
    return;

#if defined(OS_WIN)
  if (block_state == UNKNOWN) {
    std::wstring command = ExternalProtocolDialog::GetApplicationForProtocol(
                               escaped_url);
    if (command.empty()) {
      // ShellExecute won't do anything. Don't bother warning the user.
      return;
    }

    // Ask the user if they want to allow the protocol. This will call
    // LaunchUrlWithoutSecurityCheck if the user decides to accept the protocol.
    ExternalProtocolDialog::RunExternalProtocolDialog(escaped_url,
                                                      command,
                                                      render_process_host_id,
                                                      tab_contents_id);
    return;
  }
#else
  // For now, allow only whitelisted protocols to fire.
  // TODO(port): implement dialog for Mac
  if (block_state == UNKNOWN)
    return;
#endif

  // Put this work on the file thread since ShellExecute may block for a
  // significant amount of time.
  MessageLoop* loop = g_browser_process->file_thread()->message_loop();
  if (loop == NULL) {
    return;
  }

  // Otherwise the protocol is white-listed, so go ahead and launch.
  loop->PostTask(FROM_HERE,
      NewRunnableFunction(
          &ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck,
          escaped_url));
#else
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(const GURL& url) {
#if defined(OS_WIN)
  // Quote the input scheme to be sure that the command does not have
  // parameters unexpected by the external program. This url should already
  // have been escaped.
  std::string escaped_url = url.spec();
  escaped_url.insert(0, "\"");
  escaped_url += "\"";

  // According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
  // "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
  // ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
  // support URLS of 2083 chars in length, 2K is safe."
  const size_t kMaxUrlLength = 2048;
  if (escaped_url.length() > kMaxUrlLength) {
    NOTREACHED();
    return;
  }

  RegKey key;
  std::wstring registry_path = ASCIIToWide(url.scheme()) +
                               L"\\shell\\open\\command";
  key.Open(HKEY_CLASSES_ROOT, registry_path.c_str());
  if (key.Valid()) {
    DWORD size = 0;
    key.ReadValue(NULL, NULL, &size);
    if (size <= 2) {
      // ShellExecute crashes the process when the command is empty.
      // We check for "2" because it always returns the trailing NULL.
      // TODO(nsylvain): we should also add a dialog to warn on errors. See
      // bug 1136923.
      return;
    }
  }

  if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open",
                                                escaped_url.c_str(), NULL, NULL,
                                                SW_SHOWNORMAL)) <= 32) {
    // We fail to execute the call. We could display a message to the user.
    // TODO(nsylvain): we should also add a dialog to warn on errors. See
    // bug 1136923.
    return;
  }
#elif defined(OS_MACOSX)
  scoped_cftyperef<CFStringRef> string_ref(
      base::SysUTF8ToCFStringRef(url.spec()));
  if (!string_ref)
    return;

  scoped_cftyperef<CFURLRef> url_ref(CFURLCreateWithString(kCFAllocatorDefault,
                                                           string_ref,
                                                           NULL));
  if (!url_ref)
    return;

  LSOpenCFURLRef(url_ref, NULL);
#elif defined(OS_LINUX)
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(prefs::kExcludedSchemes);
}
<commit_msg>Fix Windows release compile by adding missing build_config.h include.<commit_after>// Copyright (c) 2006-2008 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/external_protocol_handler.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#endif

#include <set>

#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"

#if defined(OS_WIN)
#include "base/registry.h"
#include "chrome/browser/views/external_protocol_dialog.h"
#elif defined(OS_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#endif

// static
void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) {
  static bool is_warm = false;
  if (is_warm)
    return;
  is_warm = true;

  static const wchar_t* const denied_schemes[] = {
    L"afp",
    L"data",
    L"disk",
    L"disks",
    // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply
    // execute the file specified!  Hopefully we won't see any "file" schemes
    // because we think of file:// URLs as handled URLs, but better to be safe
    // than to let an attacker format the user's hard drive.
    L"file",
    L"hcp",
    L"javascript",
    L"ms-help",
    L"nntp",
    L"shell",
    L"vbscript",
    // view-source is a special case in chrome. When it comes through an
    // iframe or a redirect, it looks like an external protocol, but we don't
    // want to shellexecute it.
    L"view-source",
    L"vnd.ms.radio",
  };

  static const wchar_t* const allowed_schemes[] = {
    L"mailto",
    L"news",
    L"snews",
  };

  bool should_block;
  for (size_t i = 0; i < arraysize(denied_schemes); ++i) {
    if (!win_pref->GetBoolean(denied_schemes[i], &should_block)) {
      win_pref->SetBoolean(denied_schemes[i], true);
    }
  }

  for (size_t i = 0; i < arraysize(allowed_schemes); ++i) {
    if (!win_pref->GetBoolean(allowed_schemes[i], &should_block)) {
      win_pref->SetBoolean(allowed_schemes[i], false);
    }
  }
}

// static
ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState(
    const std::wstring& scheme) {
  if (scheme.length() == 1) {
    // We have a URL that looks something like:
    //   C:/WINDOWS/system32/notepad.exe
    // ShellExecuting this URL will cause the specified program to be executed.
    return BLOCK;
  }

  // Check the stored prefs.
  // TODO(pkasting): http://b/119651 This kind of thing should go in the
  // preferences on the profile, not in the local state.
  PrefService* pref = g_browser_process->local_state();
  if (pref) {  // May be NULL during testing.
    DictionaryValue* win_pref =
        pref->GetMutableDictionary(prefs::kExcludedSchemes);
    CHECK(win_pref);

    // Warm up the dictionary if needed.
    PrepopulateDictionary(win_pref);

    bool should_block;
    if (win_pref->GetBoolean(scheme, &should_block))
      return should_block ? BLOCK : DONT_BLOCK;
  }

  return UNKNOWN;
}

// static
void ExternalProtocolHandler::LaunchUrl(const GURL& url,
                                        int render_process_host_id,
                                        int tab_contents_id) {
#if !defined(OS_LINUX)
  // Escape the input scheme to be sure that the command does not
  // have parameters unexpected by the external program.
  std::string escaped_url_string = EscapeExternalHandlerValue(url.spec());
  GURL escaped_url(escaped_url_string);
  BlockState block_state = GetBlockState(ASCIIToWide(escaped_url.scheme()));
  if (block_state == BLOCK)
    return;

#if defined(OS_WIN)
  if (block_state == UNKNOWN) {
    std::wstring command = ExternalProtocolDialog::GetApplicationForProtocol(
                               escaped_url);
    if (command.empty()) {
      // ShellExecute won't do anything. Don't bother warning the user.
      return;
    }

    // Ask the user if they want to allow the protocol. This will call
    // LaunchUrlWithoutSecurityCheck if the user decides to accept the protocol.
    ExternalProtocolDialog::RunExternalProtocolDialog(escaped_url,
                                                      command,
                                                      render_process_host_id,
                                                      tab_contents_id);
    return;
  }
#else
  // For now, allow only whitelisted protocols to fire.
  // TODO(port): implement dialog for Mac
  if (block_state == UNKNOWN)
    return;
#endif

  // Put this work on the file thread since ShellExecute may block for a
  // significant amount of time.
  MessageLoop* loop = g_browser_process->file_thread()->message_loop();
  if (loop == NULL) {
    return;
  }

  // Otherwise the protocol is white-listed, so go ahead and launch.
  loop->PostTask(FROM_HERE,
      NewRunnableFunction(
          &ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck,
          escaped_url));
#else
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(const GURL& url) {
#if defined(OS_WIN)
  // Quote the input scheme to be sure that the command does not have
  // parameters unexpected by the external program. This url should already
  // have been escaped.
  std::string escaped_url = url.spec();
  escaped_url.insert(0, "\"");
  escaped_url += "\"";

  // According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
  // "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
  // ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
  // support URLS of 2083 chars in length, 2K is safe."
  const size_t kMaxUrlLength = 2048;
  if (escaped_url.length() > kMaxUrlLength) {
    NOTREACHED();
    return;
  }

  RegKey key;
  std::wstring registry_path = ASCIIToWide(url.scheme()) +
                               L"\\shell\\open\\command";
  key.Open(HKEY_CLASSES_ROOT, registry_path.c_str());
  if (key.Valid()) {
    DWORD size = 0;
    key.ReadValue(NULL, NULL, &size);
    if (size <= 2) {
      // ShellExecute crashes the process when the command is empty.
      // We check for "2" because it always returns the trailing NULL.
      // TODO(nsylvain): we should also add a dialog to warn on errors. See
      // bug 1136923.
      return;
    }
  }

  if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open",
                                                escaped_url.c_str(), NULL, NULL,
                                                SW_SHOWNORMAL)) <= 32) {
    // We fail to execute the call. We could display a message to the user.
    // TODO(nsylvain): we should also add a dialog to warn on errors. See
    // bug 1136923.
    return;
  }
#elif defined(OS_MACOSX)
  scoped_cftyperef<CFStringRef> string_ref(
      base::SysUTF8ToCFStringRef(url.spec()));
  if (!string_ref)
    return;

  scoped_cftyperef<CFURLRef> url_ref(CFURLCreateWithString(kCFAllocatorDefault,
                                                           string_ref,
                                                           NULL));
  if (!url_ref)
    return;

  LSOpenCFURLRef(url_ref, NULL);
#elif defined(OS_LINUX)
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(prefs::kExcludedSchemes);
}
<|endoftext|>