<commit_before>/*

Copyright (c) 2007, Un Shyam
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.

*/

#ifndef TORRENT_DISABLE_ENCRYPTION

#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
#define TORRENT_PE_CRYPTO_HPP_INCLUDED

#include "libtorrent/config.hpp"

#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#else
// RC4 state from libtomcrypt
struct rc4 {
	int x, y;
	unsigned char buf[256];
};

void TORRENT_EXPORT rc4_init(const unsigned char* in, unsigned long len, rc4 *state);
unsigned long TORRENT_EXPORT rc4_encrypt(unsigned char *out, unsigned long outlen, rc4 *state);
#endif

#include "libtorrent/peer_id.hpp" // For sha1_hash
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXPORT dh_key_exchange
	{
	public:
		dh_key_exchange();
		bool good() const { return true; }

		// Get local public key, always 96 bytes
		char const* get_local_key() const;

		// read remote_pubkey, generate and store shared secret in
		// m_dh_shared_secret.
		int compute_secret(const char* remote_pubkey);

		char const* get_secret() const { return m_dh_shared_secret; }

		sha1_hash const& get_hash_xor_mask() const { return m_xor_mask; }

	private:

		int get_local_key_size() const
		{ return sizeof(m_dh_local_key); }

		char m_dh_local_key[96];
		char m_dh_local_secret[96];
		char m_dh_shared_secret[96];
		sha1_hash m_xor_mask;
	};

	struct encryption_handler
	{
		virtual void set_incoming_key(unsigned char const* key, int len) = 0;
		virtual void set_outgoing_key(unsigned char const* key, int len) = 0;
		virtual void encrypt(char* pos, int len) = 0;
		virtual void decrypt(char* pos, int len) = 0;
	};

	struct rc4_handler : encryption_handler
	{
	public:
		// Input longkeys must be 20 bytes
		rc4_handler()
			: m_encrypt(false)
			, m_decrypt(false)
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
#endif
		};

		void set_incoming_key(unsigned char const* key, int len)
		{
			m_decrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_incoming, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_remote_key, len, key);
#else
			rc4_init(key, len, &m_rc4_incoming);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			decrypt(buf, 1024);
		}

		void set_outgoing_key(unsigned char const* key, int len)
		{
			m_encrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_outgoing);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_outgoing, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_local_key, len, key);
#else
			rc4_init(key, len, &m_rc4_outgoing);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			encrypt(buf, 1024);
		}

		~rc4_handler()
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_close(m_rc4_outgoing);
#endif
		};

		void encrypt(char* pos, int len)
		{
			if (!m_encrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_encrypt(m_rc4_outgoing, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_local_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_outgoing);
#endif
		}

		void decrypt(char* pos, int len)
		{
			if (!m_decrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_decrypt(m_rc4_incoming, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_remote_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_incoming);
#endif
		}

	private:
#ifdef TORRENT_USE_GCRYPT
		gcry_cipher_hd_t m_rc4_incoming;
		gcry_cipher_hd_t m_rc4_outgoing;
#elif defined TORRENT_USE_OPENSSL
		RC4_KEY m_local_key; // Key to encrypt outgoing data
		RC4_KEY m_remote_key; // Key to decrypt incoming data
#else
		rc4 m_rc4_incoming;
		rc4 m_rc4_outgoing;
#endif
		// determines whether or not encryption and decryption is enabled
		bool m_encrypt;
		bool m_decrypt;
	};

#ifdef TORRENT_USE_OPENSSL
	struct aes256_handler : encryption_handler
	{
		aes256_handler() : m_enc_pos(0), m_dec_pos(0)
		{
			EVP_CIPHER_CTX_init(&m_enc);
			EVP_CIPHER_CTX_init(&m_dec);
		}

		~aes256_handler()
		{
			EVP_CIPHER_CTX_cleanup(&m_enc);
			EVP_CIPHER_CTX_cleanup(&m_dec);
		}

		void set_incoming_key(unsigned char const* in_key, int len)
		{
			const int nrounds = 5;
			boost::uint8_t salt[8] = { 0xf1, 0x03, 0x46, 0xe2, 0xb1, 0xa8, 0x29, 0x63 };
			boost::uint8_t key[32];
			boost::uint8_t iv[32];

			int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, in_key, len, nrounds, key, iv);
			TORRENT_ASSERT(len == 32);
			EVP_EncryptInit_ex(&m_enc, EVP_aes_256_cbc(), NULL, key, iv);
			// since we're using the AES as a stream cipher, both the encrypt and
			// decrypt context will in fact only _encrypt_ stuff, so initializing
			// this as encrypt is not a typo
			EVP_EncryptInit_ex(&m_dec, EVP_aes_256_cbc(), NULL, key, iv);
			m_enc_pos = 0;
			m_dec_pos = 0;
			std::memcpy(m_enc_state, iv, sizeof(m_enc_state));
			std::memcpy(m_dec_state, iv, sizeof(m_enc_state));
		}
		void set_outgoing_key(unsigned char const* key, int len) { /* no-op */ }
		void encrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_enc_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_enc_state[m_enc_pos];
					++m_enc_pos;
					++pos;
					--len;
				}

				if (m_enc_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_enc, m_enc_state);
					m_enc_pos = 0;
				}
			}
		}

		void decrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_dec_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_dec_state[m_dec_pos];
					++m_dec_pos;
					++pos;
					--len;
				}

				if (m_dec_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_dec, m_dec_state);
					m_dec_pos = 0;
				}
			}
		}

	private:

		// we're turning the AES block-cipher into a stream cipher. This
		// function will produce the next block in the sequence of
		// block-sized buffers. We're using "Output feedback" (OFB) mode.
		void next_block(EVP_CIPHER_CTX* ctx, boost::uint8_t* pad)
		{
			int outlen = AES_BLOCK_SIZE;
			EVP_EncryptUpdate(ctx, pad, &outlen, pad, AES_BLOCK_SIZE);
			TORRENT_ASSERT(outlen == AES_BLOCK_SIZE);
		}

		EVP_CIPHER_CTX m_enc;
		EVP_CIPHER_CTX m_dec;

		boost::uint8_t m_enc_state[AES_BLOCK_SIZE];
		boost::uint8_t m_dec_state[AES_BLOCK_SIZE];
		int m_enc_pos;
		int m_dec_pos;

	};
#endif // TORRENT_USE_OPENSSL

} // namespace libtorrent

#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
#endif // TORRENT_DISABLE_ENCRYPTION

<commit_msg>fix some encryption warnings<commit_after>/*

Copyright (c) 2007, Un Shyam
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.

*/

#ifndef TORRENT_DISABLE_ENCRYPTION

#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
#define TORRENT_PE_CRYPTO_HPP_INCLUDED

#include "libtorrent/config.hpp"

#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#else
// RC4 state from libtomcrypt
struct rc4 {
	int x, y;
	unsigned char buf[256];
};

void TORRENT_EXPORT rc4_init(const unsigned char* in, unsigned long len, rc4 *state);
unsigned long TORRENT_EXPORT rc4_encrypt(unsigned char *out, unsigned long outlen, rc4 *state);
#endif

#include "libtorrent/peer_id.hpp" // For sha1_hash
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXPORT dh_key_exchange
	{
	public:
		dh_key_exchange();
		bool good() const { return true; }

		// Get local public key, always 96 bytes
		char const* get_local_key() const;

		// read remote_pubkey, generate and store shared secret in
		// m_dh_shared_secret.
		int compute_secret(const char* remote_pubkey);

		char const* get_secret() const { return m_dh_shared_secret; }

		sha1_hash const& get_hash_xor_mask() const { return m_xor_mask; }

	private:

		int get_local_key_size() const
		{ return sizeof(m_dh_local_key); }

		char m_dh_local_key[96];
		char m_dh_local_secret[96];
		char m_dh_shared_secret[96];
		sha1_hash m_xor_mask;
	};

	struct encryption_handler
	{
		virtual void set_incoming_key(unsigned char const* key, int len) = 0;
		virtual void set_outgoing_key(unsigned char const* key, int len) = 0;
		virtual void encrypt(char* pos, int len) = 0;
		virtual void decrypt(char* pos, int len) = 0;
		virtual ~encryption_handler() {}
	};

	struct rc4_handler : encryption_handler
	{
	public:
		// Input longkeys must be 20 bytes
		rc4_handler()
			: m_encrypt(false)
			, m_decrypt(false)
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
#endif
		};

		void set_incoming_key(unsigned char const* key, int len)
		{
			m_decrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_incoming, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_remote_key, len, key);
#else
			rc4_init(key, len, &m_rc4_incoming);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			decrypt(buf, 1024);
		}

		void set_outgoing_key(unsigned char const* key, int len)
		{
			m_encrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_outgoing);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_outgoing, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_local_key, len, key);
#else
			rc4_init(key, len, &m_rc4_outgoing);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			encrypt(buf, 1024);
		}

		~rc4_handler()
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_close(m_rc4_outgoing);
#endif
		};

		void encrypt(char* pos, int len)
		{
			if (!m_encrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_encrypt(m_rc4_outgoing, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_local_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_outgoing);
#endif
		}

		void decrypt(char* pos, int len)
		{
			if (!m_decrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_decrypt(m_rc4_incoming, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_remote_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_incoming);
#endif
		}

	private:
#ifdef TORRENT_USE_GCRYPT
		gcry_cipher_hd_t m_rc4_incoming;
		gcry_cipher_hd_t m_rc4_outgoing;
#elif defined TORRENT_USE_OPENSSL
		RC4_KEY m_local_key; // Key to encrypt outgoing data
		RC4_KEY m_remote_key; // Key to decrypt incoming data
#else
		rc4 m_rc4_incoming;
		rc4 m_rc4_outgoing;
#endif
		// determines whether or not encryption and decryption is enabled
		bool m_encrypt;
		bool m_decrypt;
	};

#ifdef TORRENT_USE_OPENSSL
	struct aes256_handler : encryption_handler
	{
		aes256_handler() : m_enc_pos(0), m_dec_pos(0)
		{
			EVP_CIPHER_CTX_init(&m_enc);
			EVP_CIPHER_CTX_init(&m_dec);
		}

		~aes256_handler()
		{
			EVP_CIPHER_CTX_cleanup(&m_enc);
			EVP_CIPHER_CTX_cleanup(&m_dec);
		}

		void set_incoming_key(unsigned char const* in_key, int len)
		{
			const int nrounds = 5;
			boost::uint8_t salt[8] = { 0xf1, 0x03, 0x46, 0xe2, 0xb1, 0xa8, 0x29, 0x63 };
			boost::uint8_t key[32];
			boost::uint8_t iv[32];

			EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, in_key, len, nrounds, key, iv);
			TORRENT_ASSERT(len == 32);
			EVP_EncryptInit_ex(&m_enc, EVP_aes_256_cbc(), NULL, key, iv);
			// since we're using the AES as a stream cipher, both the encrypt and
			// decrypt context will in fact only _encrypt_ stuff, so initializing
			// this as encrypt is not a typo
			EVP_EncryptInit_ex(&m_dec, EVP_aes_256_cbc(), NULL, key, iv);
			m_enc_pos = 0;
			m_dec_pos = 0;
			std::memcpy(m_enc_state, iv, sizeof(m_enc_state));
			std::memcpy(m_dec_state, iv, sizeof(m_enc_state));
		}
		void set_outgoing_key(unsigned char const* key, int len) { /* no-op */ }
		void encrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_enc_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_enc_state[m_enc_pos];
					++m_enc_pos;
					++pos;
					--len;
				}

				if (m_enc_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_enc, m_enc_state);
					m_enc_pos = 0;
				}
			}
		}

		void decrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_dec_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_dec_state[m_dec_pos];
					++m_dec_pos;
					++pos;
					--len;
				}

				if (m_dec_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_dec, m_dec_state);
					m_dec_pos = 0;
				}
			}
		}

	private:

		// we're turning the AES block-cipher into a stream cipher. This
		// function will produce the next block in the sequence of
		// block-sized buffers. We're using "Output feedback" (OFB) mode.
		void next_block(EVP_CIPHER_CTX* ctx, boost::uint8_t* pad)
		{
			int outlen = AES_BLOCK_SIZE;
			EVP_EncryptUpdate(ctx, pad, &outlen, pad, AES_BLOCK_SIZE);
			TORRENT_ASSERT(outlen == AES_BLOCK_SIZE);
		}

		EVP_CIPHER_CTX m_enc;
		EVP_CIPHER_CTX m_dec;

		boost::uint8_t m_enc_state[AES_BLOCK_SIZE];
		boost::uint8_t m_dec_state[AES_BLOCK_SIZE];
		int m_enc_pos;
		int m_dec_pos;

	};
#endif // TORRENT_USE_OPENSSL

} // namespace libtorrent

#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
#endif // TORRENT_DISABLE_ENCRYPTION

<|endoftext|>


<commit_before>/*
 * Author: Landon Fuller <landon@landonf.org>
 *
 * Copyright (c) 2015 Landon Fuller <landon@landonf.org>.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "SymbolBinder.hpp"
#include <mutex>

namespace patchmaster {

/**
 * Read a ULEB128 value from @a address.
 *
 * @param location The location from which the value should be read.
 * @param size On return, will be set to the total size of the decoded LEB128 value in bytes.
 *
 * This implementation was extracted from the PLCrashReporter DWARF code.
 */
uint64_t read_uleb128 (const void *location, std::size_t *size) {
    unsigned int shift = 0;
    size_t position = 0;

    uint64_t result = 0;
    for (const uint8_t *p = (const uint8_t *) location ;; p++) {
        /* LEB128 uses 7 bits for the number, the final bit to signal completion */
        uint8_t byte = *p;
        result |= ((uint64_t) (byte & 0x7f)) << shift;
        shift += 7;

        /* This is used to track length, so we must set it before
         * potentially terminating the loop below */
        position++;

        /* Check for terminating bit */
        if ((byte & 0x80) == 0)
            break;

        /* Check for a ULEB128 larger than 64-bits */
        if (shift >= 64) {
            PMFatal("Invalid DYLD info: ULEB128 is larger than the maximum supported size of 64 bits!");
        }
    }

    *size = position;
    return result;
}

/**
 * Read a SLEB128 value from @a location within @a mobj.
 *
 * @param location The location from which the value should be read.
 * @param size On return, will be set to the total size of the decoded LEB128 value in bytes.
 *
 * This implementation was extracted from the PLCrashReporter DWARF code.
 */
int64_t read_sleb128 (const void *location, std::size_t *size) {
    unsigned int shift = 0;
    size_t position = 0;
    int64_t result = 0;

    const uint8_t *p;
    for (p = (const uint8_t *) location ;; p++) {
        /* LEB128 uses 7 bits for the number, the final bit to signal completion */
        uint8_t byte = *p;
        result |= ((uint64_t) (byte & 0x7f)) << shift;
        shift += 7;

        /* This is used to track length, so we must set it before
         * potentially terminating the loop below */
        position++;

        /* Check for terminating bit */
        if ((byte & 0x80) == 0)
            break;

        /* Check for a SLEB128 larger than 64-bits */
        if (shift >= 64) {
            PMFatal("Invalid DYLD info: SLEB128 is larger than the maximum supported size of 64 bits!");
        }
    }

    /* Sign bit is 2nd high order bit */
    if (shift < 64 && (*p & 0x40))
        result |= -(1ULL << shift);

    *size = position;
    return result;
}

/**
 * Step the opcode stream, evaluating and returning the next opcode.
 *
 * Upon evaluating a complete symbol binding procedure, it will be dispatched to the provided bind function.
 *
 * @param image The local image to be used as the procedure's execution environment.
 * @param bind Function to call upon successfully evaluating a full bind procedure for a symbol.
 */
uint8_t bind_opstream::step (const LocalImage &image, const std::function<void(const symbol_proc &)> &bind) {
    /* Given an index into our reference libraries, update the `sym_image` state */
    auto set_current_image = [&](uint64_t image_idx) {
        if (image_idx > image._libraries->size()) {
            PMFatal("dyld bind opcode in '%s' references invalid image index %" PRIu64, image._path.c_str(), image_idx);
            return;
        }

        /* `0` is a special index referencing the current image */
        if (image_idx == 0) {
            _eval_state.sym_image = image._path;
        } else {
            _eval_state.sym_image = image._libraries->at(image_idx - 1);
        }
    };

    uint8_t op = opcode();
    switch (op) {
        case BIND_OPCODE_DONE:
            break;

        case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: {
            set_current_image(immd());
            break;
        }

        case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: {
            set_current_image(uleb128());
            break;
        }

        case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
            switch (signed_immd()) {
                    /* Enable flat resolution */
                case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
                    _eval_state.sym_image = "";
                    break;

                    /* Fetch the path of the main executable */
                case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
                    _eval_state.sym_image = LocalImage::MainExecutablePath();
                    break;

                    /* Use our own path */
                case BIND_SPECIAL_DYLIB_SELF:
                    _eval_state.sym_image = image._path.c_str();
                    break;
            }

            break;

        case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
            /* Flags are supplied as an immediate value. */
            _eval_state.sym_flags = immd();

            /* Symbol name is defined inline. */
            _eval_state.sym_name = cstring();
            break;

        case BIND_OPCODE_SET_TYPE_IMM:
            _eval_state.bind_type = immd();
            break;

        case BIND_OPCODE_SET_ADDEND_SLEB:
            _eval_state.addend = sleb128();
            break;

        case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: {
            uint8_t segment_idx = immd();
            if (segment_idx >= image._segments->size())
                PMFatal("dyld BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB in '%s' references invalid segment index %" PRIu8, image._path.c_str(), segment_idx);

            /* Compute the in-memory address from the segment reference */
            const pl_segment_command_t *segment = image._segments->at(segment_idx);
            _eval_state.bind_address = segment->vmaddr + image._vmaddr_slide;
            _eval_state.bind_address += uleb128();
            break;
        }

        case BIND_OPCODE_ADD_ADDR_ULEB:
            _eval_state.bind_address += uleb128();
            break;

        case BIND_OPCODE_DO_BIND:
            /* Perform the bind */
            bind(_eval_state.symbol_proc());

            /* This implicitly advances the current bind address by the pointer width */
            _eval_state.bind_address += sizeof(uintptr_t);
            break;

        case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
            /* Perform the bind */
            bind(_eval_state.symbol_proc());

            /* Advance the bind address */
            _eval_state.bind_address += uleb128();
            break;

        case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
            /* Perform the bind */
            bind(_eval_state.symbol_proc());

            /* Immediate offset scaled by the native pointer width */
            _eval_state.bind_address += immd() * sizeof(uintptr_t) + sizeof(uintptr_t);
            break;

        case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: {
            /* Fetch the number of addresses at which this symbol should be bound */
            uint64_t count = uleb128();

            /* Fetch the number of bytes to skip between each binding */
            uint64_t skip = uleb128();

            for (uint64_t i = 0; i < count; i++) {
                /* Perform the bind */
                bind(_eval_state.symbol_proc());

                /* Advance by the requested skip */
                _eval_state.bind_address += skip + sizeof(uintptr_t);
            }
            break;
        }

        default:
            PMFatal("Unhandled opcode: %hhx", op);
            break;
    }

    return op;
}

/**
 * Evaluate the opcode stream, passing all resolved bindings to @a bind.
 *
 * @param image The local image to be used as the procedure's execution environment.
 * @param bind The function to be called with resolved symbol bindings.
 */
void bind_opstream::evaluate (const LocalImage &image, const std::function<void(const symbol_proc &)> &bind) {
    while (!isEmpty() && step(image, bind) != BIND_OPCODE_DONE);
}

/**
 * Return the linker-provided path to the main executable.
 */
const std::string &LocalImage::MainExecutablePath () {
    static std::string path;

    /* Fetch the path only once */
    std::once_flag once;
    std::call_once(once, []{
        char *buffer = nullptr;
        uint32_t buffer_len = 0;
        while (_NSGetExecutablePath(buffer, &buffer_len) == -1) {
            free(buffer);
            buffer = (char *) malloc(buffer_len);
        }
        path = buffer;
        free(buffer);
    });

    return path;
}

/**
 * Analyze an in-memory Mach-O image.
 *
 * @param path The image path.
 * @param header The image header.
 */
LocalImage LocalImage::Analyze (const std::string &path, const pl_mach_header_t *header) {
    using namespace std;

    /* Image slide */
    intptr_t vm_slide = 0;

    /* Collect the segment and library lists, saving the __LINKEDIT info and vm_slide */
    auto segments = std::make_shared<vector<const pl_segment_command_t *>>();
    auto libraries = std::make_shared<vector<const std::string>>();
    pl_segment_command_t *linkedit = nullptr;

    const uint8_t *cmd_ptr = (const uint8_t *) header + sizeof(*header);
    for (uint32_t cmd_idx = 0; cmd_idx < header->ncmds; cmd_idx++) {
        auto cmd = (const struct load_command *) cmd_ptr;
        cmd_ptr += cmd->cmdsize;

        switch (cmd->cmd) {
            case PL_LC_SEGMENT: {
                auto segment = (pl_segment_command_t *) cmd;

                /* Use the actual load address of the __TEXT segment to calculate the dyld slide */
                if (strcmp(segment->segname, SEG_TEXT) == 0) {
                    uintptr_t load_addr = (uintptr_t) header;
                    if (segment->vmaddr < load_addr) {
                        vm_slide = load_addr - segment->vmaddr;
                    } else if (segment->vmaddr > load_addr) {
                        vm_slide = -((intptr_t) (segment->vmaddr - load_addr));
                    } else {
                        vm_slide = 0;
                    }
                } else if (strcmp(segment->segname, SEG_LINKEDIT) == 0) {
                    linkedit = segment;
                }

                /* For the purposes of indexing segments, dyld ignores zero-length segments */
                if (segment->vmsize > 0)
                    segments->push_back(segment);
                break;
            }

            case LC_LOAD_DYLIB:
            case LC_LOAD_WEAK_DYLIB:
            case LC_LOAD_UPWARD_DYLIB:
            case LC_REEXPORT_DYLIB:
            {
                auto dylib_cmd = (struct dylib_command *) cmd;

                /* Fetch the library path */
                const char *name = (const char *) (((const char *) cmd) + dylib_cmd->dylib.name.offset);
                libraries->push_back(name);
            }
        }
    }

    /* Save references to all dyld bind opcode streams */
    auto bindOpcodes = std::make_shared<vector<const bind_opstream>>();

    cmd_ptr = (const uint8_t *) header + sizeof(*header);
    for (uint32_t cmd_idx = 0; cmd_idx < header->ncmds; cmd_idx++) {
        auto cmd = (const struct load_command *) cmd_ptr;
        cmd_ptr += cmd->cmdsize;

        switch (cmd->cmd) {
            case LC_DYLD_INFO:
            case LC_DYLD_INFO_ONLY: if (linkedit != nullptr) {
                auto info = (const dyld_info_command *) cmd;
                uintptr_t linkedit_base = (linkedit->vmaddr + vm_slide) - linkedit->fileoff;

                if (info->bind_size != 0)
                    bindOpcodes->push_back(bind_opstream((const uint8_t *) (linkedit_base + info->bind_off), (size_t) info->bind_size, false));

                if (info->weak_bind_size != 0)
                    bindOpcodes->push_back(bind_opstream((const uint8_t *) (linkedit_base + info->weak_bind_off), (size_t) info->weak_bind_size, false));

                if (info->lazy_bind_size != 0)
                    bindOpcodes->push_back(bind_opstream((const uint8_t *) (linkedit_base + info->lazy_bind_off), (size_t) info->lazy_bind_size, true));
            }

            default:
                break;
        }
    }

    return LocalImage(path, header, vm_slide, libraries, segments, bindOpcodes);
}

/**
 * Evaluate all available dyld bind opcodes, passing all resolved bindings to @a binder.
 *
 * @param binder The function to be called with resolved symbol bindings.
 *
 * @return Returns true on success, or false if the opcode stream references invalid segment or image addresses.
 */
void LocalImage::rebind_symbols (const std::function<void(const bind_opstream::symbol_proc &)> &bind) {
    for (auto &&opcodes : *_bindOpcodes) {
        auto ops = opcodes;
        ops.evaluate(*this, [&bind](const bind_opstream::symbol_proc &sp) {
            // TODO - Can we handle the other types?
            if (sp.type() != BIND_TYPE_POINTER)
                return;

            /* Hand off to our caller */
            bind(sp);
        });
    }
}

}<commit_msg>When applying BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB, the offset must also include the pointer size.<commit_after>/*
 * Author: Landon Fuller <landon@landonf.org>
 *
 * Copyright (c) 2015 Landon Fuller <landon@landonf.org>.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "SymbolBinder.hpp"
#include <mutex>

namespace patchmaster {

/**
 * Read a ULEB128 value from @a address.
 *
 * @param location The location from which the value should be read.
 * @param size On return, will be set to the total size of the decoded LEB128 value in bytes.
 *
 * This implementation was extracted from the PLCrashReporter DWARF code.
 */
uint64_t read_uleb128 (const void *location, std::size_t *size) {
    unsigned int shift = 0;
    size_t position = 0;

    uint64_t result = 0;
    for (const uint8_t *p = (const uint8_t *) location ;; p++) {
        /* LEB128 uses 7 bits for the number, the final bit to signal completion */
        uint8_t byte = *p;
        result |= ((uint64_t) (byte & 0x7f)) << shift;
        shift += 7;

        /* This is used to track length, so we must set it before
         * potentially terminating the loop below */
        position++;

        /* Check for terminating bit */
        if ((byte & 0x80) == 0)
            break;

        /* Check for a ULEB128 larger than 64-bits */
        if (shift >= 64) {
            PMFatal("Invalid DYLD info: ULEB128 is larger than the maximum supported size of 64 bits!");
        }
    }

    *size = position;
    return result;
}

/**
 * Read a SLEB128 value from @a location within @a mobj.
 *
 * @param location The location from which the value should be read.
 * @param size On return, will be set to the total size of the decoded LEB128 value in bytes.
 *
 * This implementation was extracted from the PLCrashReporter DWARF code.
 */
int64_t read_sleb128 (const void *location, std::size_t *size) {
    unsigned int shift = 0;
    size_t position = 0;
    int64_t result = 0;

    const uint8_t *p;
    for (p = (const uint8_t *) location ;; p++) {
        /* LEB128 uses 7 bits for the number, the final bit to signal completion */
        uint8_t byte = *p;
        result |= ((uint64_t) (byte & 0x7f)) << shift;
        shift += 7;

        /* This is used to track length, so we must set it before
         * potentially terminating the loop below */
        position++;

        /* Check for terminating bit */
        if ((byte & 0x80) == 0)
            break;

        /* Check for a SLEB128 larger than 64-bits */
        if (shift >= 64) {
            PMFatal("Invalid DYLD info: SLEB128 is larger than the maximum supported size of 64 bits!");
        }
    }

    /* Sign bit is 2nd high order bit */
    if (shift < 64 && (*p & 0x40))
        result |= -(1ULL << shift);

    *size = position;
    return result;
}

/**
 * Step the opcode stream, evaluating and returning the next opcode.
 *
 * Upon evaluating a complete symbol binding procedure, it will be dispatched to the provided bind function.
 *
 * @param image The local image to be used as the procedure's execution environment.
 * @param bind Function to call upon successfully evaluating a full bind procedure for a symbol.
 */
uint8_t bind_opstream::step (const LocalImage &image, const std::function<void(const symbol_proc &)> &bind) {
    /* Given an index into our reference libraries, update the `sym_image` state */
    auto set_current_image = [&](uint64_t image_idx) {
        if (image_idx > image._libraries->size()) {
            PMFatal("dyld bind opcode in '%s' references invalid image index %" PRIu64, image._path.c_str(), image_idx);
            return;
        }

        /* `0` is a special index referencing the current image */
        if (image_idx == 0) {
            _eval_state.sym_image = image._path;
        } else {
            _eval_state.sym_image = image._libraries->at(image_idx - 1);
        }
    };

    uint8_t op = opcode();
    switch (op) {
        case BIND_OPCODE_DONE:
            break;

        case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: {
            set_current_image(immd());
            break;
        }

        case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: {
            set_current_image(uleb128());
            break;
        }

        case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
            switch (signed_immd()) {
                    /* Enable flat resolution */
                case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
                    _eval_state.sym_image = "";
                    break;

                    /* Fetch the path of the main executable */
                case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
                    _eval_state.sym_image = LocalImage::MainExecutablePath();
                    break;

                    /* Use our own path */
                case BIND_SPECIAL_DYLIB_SELF:
                    _eval_state.sym_image = image._path.c_str();
                    break;
            }

            break;

        case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
            /* Flags are supplied as an immediate value. */
            _eval_state.sym_flags = immd();

            /* Symbol name is defined inline. */
            _eval_state.sym_name = cstring();
            break;

        case BIND_OPCODE_SET_TYPE_IMM:
            _eval_state.bind_type = immd();
            break;

        case BIND_OPCODE_SET_ADDEND_SLEB:
            _eval_state.addend = sleb128();
            break;

        case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: {
            uint8_t segment_idx = immd();
            if (segment_idx >= image._segments->size())
                PMFatal("dyld BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB in '%s' references invalid segment index %" PRIu8, image._path.c_str(), segment_idx);

            /* Compute the in-memory address from the segment reference */
            const pl_segment_command_t *segment = image._segments->at(segment_idx);
            _eval_state.bind_address = segment->vmaddr + image._vmaddr_slide;
            _eval_state.bind_address += uleb128();
            break;
        }

        case BIND_OPCODE_ADD_ADDR_ULEB:
            _eval_state.bind_address += uleb128();
            break;

        case BIND_OPCODE_DO_BIND:
            /* Perform the bind */
            bind(_eval_state.symbol_proc());

            /* This implicitly advances the current bind address by the pointer width */
            _eval_state.bind_address += sizeof(uintptr_t);
            break;

        case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
            /* Perform the bind */
            bind(_eval_state.symbol_proc());

            /* Advance the bind address */
            _eval_state.bind_address += uleb128() + sizeof(uintptr_t);
            break;

        case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
            /* Perform the bind */
            bind(_eval_state.symbol_proc());

            /* Immediate offset scaled by the native pointer width */
            _eval_state.bind_address += immd() * sizeof(uintptr_t) + sizeof(uintptr_t);
            break;

        case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: {
            /* Fetch the number of addresses at which this symbol should be bound */
            uint64_t count = uleb128();

            /* Fetch the number of bytes to skip between each binding */
            uint64_t skip = uleb128();

            for (uint64_t i = 0; i < count; i++) {
                /* Perform the bind */
                bind(_eval_state.symbol_proc());

                /* Advance by the requested skip */
                _eval_state.bind_address += skip + sizeof(uintptr_t);
            }
            break;
        }

        default:
            PMFatal("Unhandled opcode: %hhx", op);
            break;
    }

    return op;
}

/**
 * Evaluate the opcode stream, passing all resolved bindings to @a bind.
 *
 * @param image The local image to be used as the procedure's execution environment.
 * @param bind The function to be called with resolved symbol bindings.
 */
void bind_opstream::evaluate (const LocalImage &image, const std::function<void(const symbol_proc &)> &bind) {
    while (!isEmpty() && step(image, bind) != BIND_OPCODE_DONE);
}

/**
 * Return the linker-provided path to the main executable.
 */
const std::string &LocalImage::MainExecutablePath () {
    static std::string path;

    /* Fetch the path only once */
    std::once_flag once;
    std::call_once(once, []{
        char *buffer = nullptr;
        uint32_t buffer_len = 0;
        while (_NSGetExecutablePath(buffer, &buffer_len) == -1) {
            free(buffer);
            buffer = (char *) malloc(buffer_len);
        }
        path = buffer;
        free(buffer);
    });

    return path;
}

/**
 * Analyze an in-memory Mach-O image.
 *
 * @param path The image path.
 * @param header The image header.
 */
LocalImage LocalImage::Analyze (const std::string &path, const pl_mach_header_t *header) {
    using namespace std;

    /* Image slide */
    intptr_t vm_slide = 0;

    /* Collect the segment and library lists, saving the __LINKEDIT info and vm_slide */
    auto segments = std::make_shared<vector<const pl_segment_command_t *>>();
    auto libraries = std::make_shared<vector<const std::string>>();
    pl_segment_command_t *linkedit = nullptr;

    const uint8_t *cmd_ptr = (const uint8_t *) header + sizeof(*header);
    for (uint32_t cmd_idx = 0; cmd_idx < header->ncmds; cmd_idx++) {
        auto cmd = (const struct load_command *) cmd_ptr;
        cmd_ptr += cmd->cmdsize;

        switch (cmd->cmd) {
            case PL_LC_SEGMENT: {
                auto segment = (pl_segment_command_t *) cmd;

                /* Use the actual load address of the __TEXT segment to calculate the dyld slide */
                if (strcmp(segment->segname, SEG_TEXT) == 0) {
                    uintptr_t load_addr = (uintptr_t) header;
                    if (segment->vmaddr < load_addr) {
                        vm_slide = load_addr - segment->vmaddr;
                    } else if (segment->vmaddr > load_addr) {
                        vm_slide = -((intptr_t) (segment->vmaddr - load_addr));
                    } else {
                        vm_slide = 0;
                    }
                } else if (strcmp(segment->segname, SEG_LINKEDIT) == 0) {
                    linkedit = segment;
                }

                /* For the purposes of indexing segments, dyld ignores zero-length segments */
                if (segment->vmsize > 0)
                    segments->push_back(segment);
                break;
            }

            case LC_LOAD_DYLIB:
            case LC_LOAD_WEAK_DYLIB:
            case LC_LOAD_UPWARD_DYLIB:
            case LC_REEXPORT_DYLIB:
            {
                auto dylib_cmd = (struct dylib_command *) cmd;

                /* Fetch the library path */
                const char *name = (const char *) (((const char *) cmd) + dylib_cmd->dylib.name.offset);
                libraries->push_back(name);
            }
        }
    }

    /* Save references to all dyld bind opcode streams */
    auto bindOpcodes = std::make_shared<vector<const bind_opstream>>();

    cmd_ptr = (const uint8_t *) header + sizeof(*header);
    for (uint32_t cmd_idx = 0; cmd_idx < header->ncmds; cmd_idx++) {
        auto cmd = (const struct load_command *) cmd_ptr;
        cmd_ptr += cmd->cmdsize;

        switch (cmd->cmd) {
            case LC_DYLD_INFO:
            case LC_DYLD_INFO_ONLY: if (linkedit != nullptr) {
                auto info = (const dyld_info_command *) cmd;
                uintptr_t linkedit_base = (linkedit->vmaddr + vm_slide) - linkedit->fileoff;

                if (info->bind_size != 0)
                    bindOpcodes->push_back(bind_opstream((const uint8_t *) (linkedit_base + info->bind_off), (size_t) info->bind_size, false));

                if (info->weak_bind_size != 0)
                    bindOpcodes->push_back(bind_opstream((const uint8_t *) (linkedit_base + info->weak_bind_off), (size_t) info->weak_bind_size, false));

                if (info->lazy_bind_size != 0)
                    bindOpcodes->push_back(bind_opstream((const uint8_t *) (linkedit_base + info->lazy_bind_off), (size_t) info->lazy_bind_size, true));
            }

            default:
                break;
        }
    }

    return LocalImage(path, header, vm_slide, libraries, segments, bindOpcodes);
}

/**
 * Evaluate all available dyld bind opcodes, passing all resolved bindings to @a binder.
 *
 * @param binder The function to be called with resolved symbol bindings.
 *
 * @return Returns true on success, or false if the opcode stream references invalid segment or image addresses.
 */
void LocalImage::rebind_symbols (const std::function<void(const bind_opstream::symbol_proc &)> &bind) {
    for (auto &&opcodes : *_bindOpcodes) {
        auto ops = opcodes;
        ops.evaluate(*this, [&bind](const bind_opstream::symbol_proc &sp) {
            // TODO - Can we handle the other types?
            if (sp.type() != BIND_TYPE_POINTER)
                return;

            /* Hand off to our caller */
            bind(sp);
        });
    }
}

}<|endoftext|>


<commit_before>#include "pcl/console/parse.h"
#include "boost/filesystem.hpp"
#include "pcl/io/io.h"
#include "pcl/io/ply_io.h"

int subsample( int argc, char** argv )
{
    bool        valid_input             = true;
    std::string cloud_path              = "./cloud.ply";
    float       N                       = 1000.;

    // cloud
    if ( (pcl::console::parse_argument( argc, argv, "--cloud", cloud_path) < 0)
         || !boost::filesystem::exists( cloud_path ) )
    {
        std::cerr << "[" << __func__ << "]: " << "--cloud does not exist: " << cloud_path << std::endl;
        valid_input = false;
    }

    if ( pcl::console::parse_argument( argc, argv, "--N", N) < 0 )
    {
        std::cerr << "[" << __func__ << "]: " << "Need N to work" << std::endl;
        valid_input = false;
    }

    if ( !valid_input || (pcl::console::find_switch(argc,argv,"-h")) || (pcl::console::find_switch(argc,argv,"--help")) )
    {
        std::cout << "[" << __func__ << "]: " << "Usage: " << argv[0] << "--subsample\n"
                  << "\t--cloud " << cloud_path << "\n"
                  << "\t--N " << N << "\n";

        return EXIT_FAILURE;
    }

    srand( 123456 );

    pcl::PointCloud<pcl::PointXYZ> cloud, out_cloud;
    out_cloud.reserve( cloud.size() );
    std::cout << "reading " << cloud_path << std::endl;
    pcl::io::loadPLYFile( cloud_path, cloud );
    float chance = N / (float)cloud.size();
    for ( size_t pid = 0; pid != cloud.size(); ++pid )
    {
        if ( (rand() / (float)RAND_MAX) < chance )
        {
            out_cloud.push_back( cloud.at(pid) );
        }
    }

    std::stringstream ss;
    ss << cloud_path.substr( 0, cloud_path.find(".ply") ) << "_" << (int)N << ".ply";
    pcl::io::savePLYFile( ss.str(), out_cloud );

    return EXIT_SUCCESS;
}
<commit_msg>- added scene normalization to subsample - added temporary toy example cloud to subsample.cpp<commit_after>#include "pcl/console/parse.h"
#include "boost/filesystem.hpp"
#include "pcl/io/io.h"
#include "pcl/io/ply_io.h"
#include "pcl/common/common.h"

int subsample( int argc, char** argv )
{
    typedef Eigen::Vector4f Position;

    bool        valid_input             = true;
    std::string cloud_path              = "./cloud.ply";
    float       N                       = 1000.;

    // cloud
    if ( (pcl::console::parse_argument( argc, argv, "--cloud", cloud_path) < 0)
         || !boost::filesystem::exists( cloud_path ) )
    {
        std::cerr << "[" << __func__ << "]: " << "--cloud does not exist: " << cloud_path << std::endl;
        valid_input = false;
    }

    if ( pcl::console::parse_argument( argc, argv, "--N", N) < 0 )
    {
        std::cerr << "[" << __func__ << "]: " << "Need N to work" << std::endl;
        valid_input = false;
    }

    Position sceneSize; sceneSize << 10, 10, 10, 1;

    if ( !valid_input || (pcl::console::find_switch(argc,argv,"-h")) || (pcl::console::find_switch(argc,argv,"--help")) )
    {
        std::cout << "[" << __func__ << "]: " << "Usage: " << argv[0] << "--subsample\n"
                  << "\t--cloud " << cloud_path << "\n"
                  << "\t--N " << N << "\n";

        return EXIT_FAILURE;
    }

    srand( 123456 );

    pcl::PointCloud<pcl::PointXYZ> cloud, out_cloud;
    out_cloud.reserve( cloud.size() );
    std::cout << "reading " << cloud_path << std::endl;
    pcl::io::loadPLYFile( cloud_path, cloud );

    Position min_pt, max_pt;
    pcl::getMinMax3D( cloud, min_pt, max_pt );
    std::cout << "min: " << min_pt.transpose() << ", max: " << max_pt.transpose() << std::endl;
    Position div = (max_pt - min_pt);
    div(0) = sceneSize(0) / div(0);
    div(1) = sceneSize(1) / div(1);
    if ( div(2) > 0.f )
        div(2) = sceneSize(2) / div(2);

#if 0
    float chance = N / (float)cloud.size();
    for ( size_t pid = 0; pid != cloud.size(); ++pid )
    {
        if ( (rand() / (float)RAND_MAX) < chance )
        {
            auto pnt = cloud.at(pid);
            pnt.getVector4fMap() -= min_pt;
            pnt.getVector4fMap()(0) *= div(0);
            pnt.getVector4fMap()(1) *= div(1);
            pnt.getVector4fMap()(2) *= div(2);
            std::cout << "adding " << pnt.getVector3fMap().transpose() << " from " << cloud.at(pid).getVector3fMap().transpose() << std::endl;
            out_cloud.push_back( pnt );
        }
    }
#else
    out_cloud.push_back( pcl::PointXYZ(5,5,0) );
    out_cloud.push_back( pcl::PointXYZ(5,6,0) );
    out_cloud.push_back( pcl::PointXYZ(6,5,0) );
    out_cloud.push_back( pcl::PointXYZ(6,6,0) );
#endif

    std::stringstream ss;
    ss << cloud_path.substr( 0, cloud_path.find(".ply") ) << "_" << (int)N << ".ply";
    pcl::io::savePLYFile( ss.str(), out_cloud );

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkPictureImageFilter.h"

// This GM exercises the SkPictureImageFilter ImageFilter class.

class PictureImageFilterGM : public skiagm::GM {
public:
    PictureImageFilterGM() {
    }

protected:
    virtual SkString onShortName() SK_OVERRIDE {
        return SkString("pictureimagefilter");
    }

    void makePicture() {
        SkCanvas* canvas = fPicture.beginRecording(100, 100);
        canvas->clear(0x00000000);
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setColor(0xFFFFFFFF);
        paint.setTextSize(SkIntToScalar(96));
        const char* str = "e";
        canvas->drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
        fPicture.endRecording();
    }

    virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(500, 150); }

    virtual void onOnceBeforeDraw() SK_OVERRIDE {
        this->makePicture();
    }

    static void fillRectFiltered(SkCanvas* canvas, const SkRect& clipRect, SkImageFilter* filter) {
        SkPaint paint;
        paint.setImageFilter(filter);
        canvas->save();
        canvas->clipRect(clipRect);
        canvas->drawPaint(paint);
        canvas->restore();
    }

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        canvas->clear(0x00000000);
        {
            SkRect srcRect = SkRect::MakeXYWH(20, 20, 30, 30);
            SkRect emptyRect = SkRect::MakeXYWH(20, 20, 0, 0);
            SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
            SkAutoTUnref<SkImageFilter> pictureSource(new SkPictureImageFilter(&fPicture));
            SkAutoTUnref<SkImageFilter> pictureSourceSrcRect(new SkPictureImageFilter(&fPicture, srcRect));
            SkAutoTUnref<SkImageFilter> pictureSourceEmptyRect(new SkPictureImageFilter(&fPicture, emptyRect));

            // Draw the picture unscaled.
            fillRectFiltered(canvas, bounds, pictureSource);
            canvas->translate(SkIntToScalar(100), 0);

            // Draw an unscaled subset of the source picture.
            fillRectFiltered(canvas, bounds, pictureSourceSrcRect);
            canvas->translate(SkIntToScalar(100), 0);

            // Draw the picture to an empty rect (should draw nothing).
            fillRectFiltered(canvas, bounds, pictureSourceEmptyRect);
            canvas->translate(SkIntToScalar(100), 0);
        }
    }

private:
    SkPicture fPicture;
    typedef GM INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

DEF_GM( return new PictureImageFilterGM; )
<commit_msg>Don't run the GM in serialization modes.<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkPictureImageFilter.h"

// This GM exercises the SkPictureImageFilter ImageFilter class.

class PictureImageFilterGM : public skiagm::GM {
public:
    PictureImageFilterGM() {
    }

protected:
    virtual SkString onShortName() SK_OVERRIDE {
        return SkString("pictureimagefilter");
    }

    void makePicture() {
        SkCanvas* canvas = fPicture.beginRecording(100, 100);
        canvas->clear(0x00000000);
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setColor(0xFFFFFFFF);
        paint.setTextSize(SkIntToScalar(96));
        const char* str = "e";
        canvas->drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
        fPicture.endRecording();
    }

    virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(500, 150); }

    virtual void onOnceBeforeDraw() SK_OVERRIDE {
        this->makePicture();
    }

    static void fillRectFiltered(SkCanvas* canvas, const SkRect& clipRect, SkImageFilter* filter) {
        SkPaint paint;
        paint.setImageFilter(filter);
        canvas->save();
        canvas->clipRect(clipRect);
        canvas->drawPaint(paint);
        canvas->restore();
    }

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        canvas->clear(0x00000000);
        {
            SkRect srcRect = SkRect::MakeXYWH(20, 20, 30, 30);
            SkRect emptyRect = SkRect::MakeXYWH(20, 20, 0, 0);
            SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
            SkAutoTUnref<SkImageFilter> pictureSource(new SkPictureImageFilter(&fPicture));
            SkAutoTUnref<SkImageFilter> pictureSourceSrcRect(new SkPictureImageFilter(&fPicture, srcRect));
            SkAutoTUnref<SkImageFilter> pictureSourceEmptyRect(new SkPictureImageFilter(&fPicture, emptyRect));

            // Draw the picture unscaled.
            fillRectFiltered(canvas, bounds, pictureSource);
            canvas->translate(SkIntToScalar(100), 0);

            // Draw an unscaled subset of the source picture.
            fillRectFiltered(canvas, bounds, pictureSourceSrcRect);
            canvas->translate(SkIntToScalar(100), 0);

            // Draw the picture to an empty rect (should draw nothing).
            fillRectFiltered(canvas, bounds, pictureSourceEmptyRect);
            canvas->translate(SkIntToScalar(100), 0);
        }
    }

    // SkPictureImageFilter doesn't support serialization yet.
    virtual uint32_t onGetFlags() const SK_OVERRIDE {
        return kSkipPicture_Flag            |
               kSkipPipe_Flag               |
               kSkipPipeCrossProcess_Flag   |
               kSkipTiled_Flag              |
               kSkipScaledReplay_Flag;
    }

private:
    SkPicture fPicture;
    typedef GM INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

DEF_GM( return new PictureImageFilterGM; )
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <random>

using namespace std;

class Card {
private:
	string rank;
	string suit;
public:
	// Constuctors
	Card() {};
	Card(string r, string s) : rank(r), suit(s) {};

	// Destructors
	~Card() {};

	// Accessors
	string getRank() const { return rank; }
	string getSuit() const { return suit; }

	// Mutators
	void setRank(string r) { this->rank = rank; }
	void setSuit(string s) { this->suit = suit; }
};

int randomNumber(int num)
{
	random_device rd;
	mt19937 gn(rd());
	uniform_int_distribution<int> range(0, num);
	return range(gn);
}

int main() {

	// Define deck rank & suits
	const vector<string> rank = { "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King" };
	const vector<string> suit = { "\3", "\4", "\5", "\6" };

	// Create deck of cards
	vector<Card> deck;

	// Fill deck of cards
	for (auto s : suit)
		for (auto r : rank) {
			Card c(r, s);
			deck.push_back(c);
		}

	// Pick a card
	for (unsigned int i = 0; i < 20; ++i) {
		int rNum = randomNumber(deck.size() - 1);
		cout << deck[rNum].getRank() << " of " << deck[rNum].getSuit() << endl;
	}

	cin.get();
	return 0;
}<commit_msg>Comment change<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <random>

using namespace std;

class Card {
private:
	string rank;
	string suit;
public:
	// Constuctors
	Card() {};
	Card(string r, string s) : rank(r), suit(s) {};

	// Destructors
	~Card() {};

	// Accessors
	string getRank() const { return rank; }
	string getSuit() const { return suit; }

	// Mutators
	void setRank(string r) { this->rank = rank; }
	void setSuit(string s) { this->suit = suit; }
};

int randomNumber(int num)
{
	random_device rd;
	mt19937 gn(rd());
	uniform_int_distribution<int> range(0, num);
	return range(gn);
}

int main() {

	// Define deck ranks & suits
	const vector<string> rank = { "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King" };
	const vector<string> suit = { "\3", "\4", "\5", "\6" };

	// Create deck of cards
	vector<Card> deck;

	// Fill deck of cards
	for (auto s : suit)
		for (auto r : rank) {
			Card c(r, s);
			deck.push_back(c);
		}

	// Pick a card
	for (unsigned int i = 0; i < 20; ++i) {
		int rNum = randomNumber(deck.size() - 1);
		cout << deck[rNum].getRank() << " of " << deck[rNum].getSuit() << endl;
	}

	cin.get();
	return 0;
}<|endoftext|>


<commit_before>// @(#)root/graf:$Id$
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TROOT.h"
#include "Strlen.h"
#include "TWbox.h"
#include "TColor.h"
#include "TVirtualPad.h"
#include "TVirtualX.h"
#include "TPoint.h"

ClassImp(TWbox)

//______________________________________________________________________________
//
// a TWbox is a TBox with a bordersize and a bordermode.
//
//Begin_Html
/*

*/
//End_Html

//______________________________________________________________________________
TWbox::TWbox(): TBox()
{
   // wbox default constructor.
}

//______________________________________________________________________________
TWbox::TWbox(Double_t x1, Double_t y1,Double_t x2, Double_t  y2,
             Color_t color ,Short_t bordersize ,Short_t bordermode)
       :TBox(x1,y1,x2,y2)
{
   // wbox normal constructor.
   //
   // a WBOX is a box with a bordersize and a bordermode
   // the bordersize is in pixels
   // bordermode = -1 box looks as it is behind the screen
   // bordermode = 0  no special effects
   // bordermode = 1  box looks as it is in front of the screen

   fBorderSize  = bordersize;
   fBorderMode  = bordermode;
   SetFillColor(color);
   SetFillStyle(1001);
}

//______________________________________________________________________________
TWbox::~TWbox()
{
   // wbox default destructor.
}

//______________________________________________________________________________
TWbox::TWbox(const TWbox &wbox) : TBox(wbox)
{
   // wbox copy constructor.

   ((TWbox&)wbox).Copy(*this);
}

//______________________________________________________________________________
void TWbox::Copy(TObject &obj) const
{
   // Copy this wbox to wbox.

   TBox::Copy(obj);
   ((TWbox&)obj).fBorderSize  = fBorderSize;
   ((TWbox&)obj).fBorderMode  = fBorderMode;
}

//______________________________________________________________________________
void TWbox::Draw(Option_t *option)
{
   // Draw this wbox with its current attributes.

   AppendPad(option);
}

//______________________________________________________________________________
void TWbox::DrawWbox(Double_t x1, Double_t y1,Double_t x2, Double_t  y2,
                     Color_t color ,Short_t bordersize ,Short_t bordermode)
{
   // Draw this wbox with new coordinates.

   TWbox *newwbox = new TWbox(x1,y1,x2,y2,color,bordersize,bordermode);
   newwbox->SetBit(kCanDelete);
   newwbox->AppendPad();
}

//______________________________________________________________________________
void TWbox::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   // Execute action corresponding to one event.
   //
   //  This member function is called when a WBOX object is clicked.

   TBox::ExecuteEvent(event, px, py);
}

//______________________________________________________________________________
void TWbox::Paint(Option_t *)
{
   // Paint this wbox with its current attributes.

   PaintWbox(fX1, fY1, fX2, fY2, GetFillColor(), fBorderSize, fBorderMode);
}

//______________________________________________________________________________
void TWbox::PaintWbox(Double_t x1, Double_t y1, Double_t x2, Double_t  y2,
                      Color_t color, Short_t bordersize, Short_t bordermode)
{
   // Draw this wbox with new coordinates.

   // Draw first wbox as a normal filled box
   TBox::PaintBox(x1, y1, x2, y2);

   // then paint 3d frame (depending on bordermode)
   if (!IsTransparent())
      PaintFrame(x1, y1, x2, y2, color, bordersize, bordermode, kTRUE);
}

//______________________________________________________________________________
void TWbox::PaintFrame(Double_t x1, Double_t y1,Double_t x2, Double_t  y2,
                       Color_t color, Short_t bordersize, Short_t bordermode,
                       Bool_t tops)
{
   // Paint a 3D frame around a box.

   if (bordermode == 0) return;
   if (bordersize <= 0) bordersize = 2;

   Short_t pxl,pyl,pxt,pyt,px1,py1,px2,py2;
   Double_t xl, xt, yl, yt;

   // Compute real left bottom & top right of the box in pixels
   px1 = gPad->XtoPixel(x1);   py1 = gPad->YtoPixel(y1);
   px2 = gPad->XtoPixel(x2);   py2 = gPad->YtoPixel(y2);
   if (px1 < px2) {pxl = px1; pxt = px2; xl = x1; xt = x2; }
   else           {pxl = px2; pxt = px1; xl = x2; xt = x1;}
   if (py1 > py2) {pyl = py1; pyt = py2; yl = y1; yt = y2;}
   else           {pyl = py2; pyt = py1; yl = y2; yt = y1;}

   if (!gPad->IsBatch()) {
      TPoint frame[7];

      // GetDarkColor() and GetLightColor() use GetFillColor()
      Color_t oldcolor = GetFillColor();
      SetFillColor(color);
      TAttFill::Modify();

      // Draw top&left part of the box
      frame[0].fX = pxl;                 frame[0].fY = pyl;
      frame[1].fX = pxl + bordersize;    frame[1].fY = pyl - bordersize;
      frame[2].fX = frame[1].fX;         frame[2].fY = pyt + bordersize;
      frame[3].fX = pxt - bordersize;    frame[3].fY = frame[2].fY;
      frame[4].fX = pxt;                 frame[4].fY = pyt;
      frame[5].fX = pxl;                 frame[5].fY = pyt;
      frame[6].fX = pxl;                 frame[6].fY = pyl;

      if (bordermode == -1) gVirtualX->SetFillColor(GetDarkColor());
      else                  gVirtualX->SetFillColor(GetLightColor());
      gVirtualX->DrawFillArea(7, frame);

      // Draw bottom&right part of the box
      frame[0].fX = pxl;                 frame[0].fY = pyl;
      frame[1].fX = pxl + bordersize;    frame[1].fY = pyl - bordersize;
      frame[2].fX = pxt - bordersize;    frame[2].fY = frame[1].fY;
      frame[3].fX = frame[2].fX;         frame[3].fY = pyt + bordersize;
      frame[4].fX = pxt;                 frame[4].fY = pyt;
      frame[5].fX = pxt;                 frame[5].fY = pyl;
      frame[6].fX = pxl;                 frame[6].fY = pyl;

      if (bordermode == -1) gVirtualX->SetFillColor(TColor::GetColorBright(GetFillColor()));
      else                  gVirtualX->SetFillColor(TColor::GetColorDark(GetFillColor()));
      gVirtualX->DrawFillArea(7, frame);

      gVirtualX->SetFillColor(-1);
      SetFillColor(oldcolor);
   }

   if (!tops) return;

   // same for PostScript
   // Double_t dx   = (xt - xl) *Double_t(bordersize)/Double_t(pxt - pxl);
   // Int_t border = gVirtualPS->XtoPS(xt) - gVirtualPS->XtoPS(xt-dx);

   gPad->PaintBorderPS(xl, yl, xt, yt, bordermode, bordersize,
                         GetDarkColor(), GetLightColor());
}

//______________________________________________________________________________
void TWbox::SavePrimitive(ostream &out, Option_t * /*= ""*/)
{
   // Save primitive as a C++ statement(s) on output stream out

   if (gROOT->ClassSaved(TWbox::Class())) {
      out<<"   ";
   } else {
      out<<"   TWbox *";
   }
   out<<"wbox = new TWbox("<<fX1<<","<<fY1<<","<<fX2<<","<<fY2<<");"<<endl;

   SaveFillAttributes(out,"wbox",0,1001);
   SaveLineAttributes(out,"wbox",1,1,1);

   out<<"   wbox->Draw();"<<endl;
}
<commit_msg>- initialize members (coverity)<commit_after>// @(#)root/graf:$Id$
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TROOT.h"
#include "Strlen.h"
#include "TWbox.h"
#include "TColor.h"
#include "TVirtualPad.h"
#include "TVirtualX.h"
#include "TPoint.h"

ClassImp(TWbox)

//______________________________________________________________________________
//
// a TWbox is a TBox with a bordersize and a bordermode.
//
//Begin_Html
/*

*/
//End_Html

//______________________________________________________________________________
TWbox::TWbox(): TBox()
{
   // wbox default constructor.

   fBorderSize  = 0;
   fBorderMode  = 0;
}

//______________________________________________________________________________
TWbox::TWbox(Double_t x1, Double_t y1,Double_t x2, Double_t  y2,
             Color_t color ,Short_t bordersize ,Short_t bordermode)
       :TBox(x1,y1,x2,y2)
{
   // wbox normal constructor.
   //
   // a WBOX is a box with a bordersize and a bordermode
   // the bordersize is in pixels
   // bordermode = -1 box looks as it is behind the screen
   // bordermode = 0  no special effects
   // bordermode = 1  box looks as it is in front of the screen

   fBorderSize  = bordersize;
   fBorderMode  = bordermode;
   SetFillColor(color);
   SetFillStyle(1001);
}

//______________________________________________________________________________
TWbox::~TWbox()
{
   // wbox default destructor.
}

//______________________________________________________________________________
TWbox::TWbox(const TWbox &wbox) : TBox(wbox)
{
   // wbox copy constructor.

   ((TWbox&)wbox).Copy(*this);
}

//______________________________________________________________________________
void TWbox::Copy(TObject &obj) const
{
   // Copy this wbox to wbox.

   TBox::Copy(obj);
   ((TWbox&)obj).fBorderSize  = fBorderSize;
   ((TWbox&)obj).fBorderMode  = fBorderMode;
}

//______________________________________________________________________________
void TWbox::Draw(Option_t *option)
{
   // Draw this wbox with its current attributes.

   AppendPad(option);
}

//______________________________________________________________________________
void TWbox::DrawWbox(Double_t x1, Double_t y1,Double_t x2, Double_t  y2,
                     Color_t color ,Short_t bordersize ,Short_t bordermode)
{
   // Draw this wbox with new coordinates.

   TWbox *newwbox = new TWbox(x1,y1,x2,y2,color,bordersize,bordermode);
   newwbox->SetBit(kCanDelete);
   newwbox->AppendPad();
}

//______________________________________________________________________________
void TWbox::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   // Execute action corresponding to one event.
   //
   //  This member function is called when a WBOX object is clicked.

   TBox::ExecuteEvent(event, px, py);
}

//______________________________________________________________________________
void TWbox::Paint(Option_t *)
{
   // Paint this wbox with its current attributes.

   PaintWbox(fX1, fY1, fX2, fY2, GetFillColor(), fBorderSize, fBorderMode);
}

//______________________________________________________________________________
void TWbox::PaintWbox(Double_t x1, Double_t y1, Double_t x2, Double_t  y2,
                      Color_t color, Short_t bordersize, Short_t bordermode)
{
   // Draw this wbox with new coordinates.

   // Draw first wbox as a normal filled box
   TBox::PaintBox(x1, y1, x2, y2);

   // then paint 3d frame (depending on bordermode)
   if (!IsTransparent())
      PaintFrame(x1, y1, x2, y2, color, bordersize, bordermode, kTRUE);
}

//______________________________________________________________________________
void TWbox::PaintFrame(Double_t x1, Double_t y1,Double_t x2, Double_t  y2,
                       Color_t color, Short_t bordersize, Short_t bordermode,
                       Bool_t tops)
{
   // Paint a 3D frame around a box.

   if (bordermode == 0) return;
   if (bordersize <= 0) bordersize = 2;

   Short_t pxl,pyl,pxt,pyt,px1,py1,px2,py2;
   Double_t xl, xt, yl, yt;

   // Compute real left bottom & top right of the box in pixels
   px1 = gPad->XtoPixel(x1);   py1 = gPad->YtoPixel(y1);
   px2 = gPad->XtoPixel(x2);   py2 = gPad->YtoPixel(y2);
   if (px1 < px2) {pxl = px1; pxt = px2; xl = x1; xt = x2; }
   else           {pxl = px2; pxt = px1; xl = x2; xt = x1;}
   if (py1 > py2) {pyl = py1; pyt = py2; yl = y1; yt = y2;}
   else           {pyl = py2; pyt = py1; yl = y2; yt = y1;}

   if (!gPad->IsBatch()) {
      TPoint frame[7];

      // GetDarkColor() and GetLightColor() use GetFillColor()
      Color_t oldcolor = GetFillColor();
      SetFillColor(color);
      TAttFill::Modify();

      // Draw top&left part of the box
      frame[0].fX = pxl;                 frame[0].fY = pyl;
      frame[1].fX = pxl + bordersize;    frame[1].fY = pyl - bordersize;
      frame[2].fX = frame[1].fX;         frame[2].fY = pyt + bordersize;
      frame[3].fX = pxt - bordersize;    frame[3].fY = frame[2].fY;
      frame[4].fX = pxt;                 frame[4].fY = pyt;
      frame[5].fX = pxl;                 frame[5].fY = pyt;
      frame[6].fX = pxl;                 frame[6].fY = pyl;

      if (bordermode == -1) gVirtualX->SetFillColor(GetDarkColor());
      else                  gVirtualX->SetFillColor(GetLightColor());
      gVirtualX->DrawFillArea(7, frame);

      // Draw bottom&right part of the box
      frame[0].fX = pxl;                 frame[0].fY = pyl;
      frame[1].fX = pxl + bordersize;    frame[1].fY = pyl - bordersize;
      frame[2].fX = pxt - bordersize;    frame[2].fY = frame[1].fY;
      frame[3].fX = frame[2].fX;         frame[3].fY = pyt + bordersize;
      frame[4].fX = pxt;                 frame[4].fY = pyt;
      frame[5].fX = pxt;                 frame[5].fY = pyl;
      frame[6].fX = pxl;                 frame[6].fY = pyl;

      if (bordermode == -1) gVirtualX->SetFillColor(TColor::GetColorBright(GetFillColor()));
      else                  gVirtualX->SetFillColor(TColor::GetColorDark(GetFillColor()));
      gVirtualX->DrawFillArea(7, frame);

      gVirtualX->SetFillColor(-1);
      SetFillColor(oldcolor);
   }

   if (!tops) return;

   // same for PostScript
   // Double_t dx   = (xt - xl) *Double_t(bordersize)/Double_t(pxt - pxl);
   // Int_t border = gVirtualPS->XtoPS(xt) - gVirtualPS->XtoPS(xt-dx);

   gPad->PaintBorderPS(xl, yl, xt, yt, bordermode, bordersize,
                         GetDarkColor(), GetLightColor());
}

//______________________________________________________________________________
void TWbox::SavePrimitive(ostream &out, Option_t * /*= ""*/)
{
   // Save primitive as a C++ statement(s) on output stream out

   if (gROOT->ClassSaved(TWbox::Class())) {
      out<<"   ";
   } else {
      out<<"   TWbox *";
   }
   out<<"wbox = new TWbox("<<fX1<<","<<fY1<<","<<fX2<<","<<fY2<<");"<<endl;

   SaveFillAttributes(out,"wbox",0,1001);
   SaveLineAttributes(out,"wbox",1,1,1);

   out<<"   wbox->Draw();"<<endl;
}
<|endoftext|>


<commit_before>#include "Runtime/World/CScriptActor.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/CPlayerState.hpp"
#include "Runtime/Camera/CGameCamera.hpp"
#include "Runtime/Character/IAnimReader.hpp"
#include "Runtime/MP1/World/CActorContraption.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CDamageVulnerability.hpp"
#include "Runtime/World/CScriptColorModulate.hpp"
#include "Runtime/World/CScriptTrigger.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

#include <zeus/CEulerAngles.hpp>

namespace urde {

CScriptActor::CScriptActor(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                           CModelData&& mData, const zeus::CAABox& aabb, float mass, float zMomentum,
                           const CMaterialList& matList, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
                           const CActorParameters& actParms, bool looping, bool active, s32 shaderIdx, float xrayAlpha,
                           bool noThermalHotZ, bool castsShadow, bool scaleAdvancementDelta, bool materialFlag54)
: CPhysicsActor(uid, active, name, info, xf, std::move(mData), matList, aabb, SMoverData(mass), actParms, 0.3f, 0.1f)
, x258_initialHealth(hInfo)
, x260_currentHealth(hInfo)
, x268_damageVulnerability(dVuln)
, x2d0_fadeInTime(actParms.x5c_fadeInTime)
, x2d4_fadeOutTime(actParms.x60_fadeOutTime)
, x2d8_shaderIdx(shaderIdx)
, x2dc_xrayAlpha(xrayAlpha) {
  x2e2_24_noThermalHotZ = noThermalHotZ;
  x2e2_27_xrayAlphaEnabled = !zeus::close_enough(1.f, xrayAlpha);
  x2e2_29_processModelFlags = (x2e2_27_xrayAlphaEnabled || x2e2_24_noThermalHotZ || x2d8_shaderIdx != 0);
  x2e2_30_scaleAdvancementDelta = scaleAdvancementDelta;
  x2e2_31_materialFlag54 = materialFlag54;

  if (x64_modelData && (x64_modelData->HasAnimData() || x64_modelData->HasNormalModel()) && castsShadow) {
    CreateShadow(true);
  }

  if (x64_modelData && x64_modelData->HasAnimData()) {
    x64_modelData->EnableLooping(looping);
  }

  x150_momentum = zeus::CVector3f(0.f, 0.f, zMomentum);
}

void CScriptActor::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CScriptActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  switch (msg) {
  case EScriptObjectMessage::InitializedInArea:
    for (const SConnection& conn : x20_conns) {
      if (conn.x0_state != EScriptObjectState::InheritBounds || conn.x4_msg != EScriptObjectMessage::Activate) {
        continue;
      }

      const auto search = mgr.GetIdListForScript(conn.x8_objId);
      for (auto it = search.first; it != search.second; ++it) {
        if (TCastToConstPtr<CScriptTrigger>(mgr.GetObjectById(it->second))) {
          x2e0_triggerId = it->second;
          break;
        }
      }
    }

    if (x2e2_31_materialFlag54) {
      CActor::AddMaterial(EMaterialTypes::Unknown54, mgr);
    }
    break;
  case EScriptObjectMessage::Reset:
    x2e2_25_dead = false;
    x260_currentHealth = x258_initialHealth;
    break;
  case EScriptObjectMessage::Increment:
    if (!GetActive()) {
      mgr.SendScriptMsg(this, x8_uid, EScriptObjectMessage::Activate);
      CScriptColorModulate::FadeInHelper(mgr, x8_uid, x2d0_fadeInTime);
    }
    break;
  case EScriptObjectMessage::Decrement:
    CScriptColorModulate::FadeOutHelper(mgr, x8_uid, x2d4_fadeOutTime);
    break;
  default:
    break;
  }

  CActor::AcceptScriptMsg(msg, uid, mgr);
}

void CScriptActor::Think(float dt, CStateManager& mgr) {
  if (!GetActive()) {
    return;
  }

  if (HasModelData() && x64_modelData->HasAnimData()) {
    const bool timeRemaining = x64_modelData->GetAnimationData()->IsAnimTimeRemaining(dt - FLT_EPSILON, "Whole Body");
    const bool loop = x64_modelData->GetIsLoop();

    const SAdvancementDeltas deltas = CActor::UpdateAnimation(dt, mgr, true);

    if (timeRemaining || loop) {
      x2e2_26_animating = true;

      if (x2e2_30_scaleAdvancementDelta) {
        MoveToOR(x34_transform.rotate(x64_modelData->GetScale() * x34_transform.transposeRotate(deltas.x0_posDelta)),
                 dt);
      } else {
        MoveToOR(deltas.x0_posDelta, dt);
      }

      //if (TCastToPtr<MP1::CActorContraption>(this))
        //printf("DEL %f\n", zeus::radToDeg(zeus::CEulerAngles(deltas.xc_rotDelta).z()));
        //printf("DEL %f %f %f %f\n", float(deltas.xc_rotDelta[0]), float(deltas.xc_rotDelta[1]), float(deltas.xc_rotDelta[2]), float(deltas.xc_rotDelta[3]));
      RotateToOR(deltas.xc_rotDelta, dt);
    }

    if (!timeRemaining && x2e2_26_animating && !loop) {
      SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None);
      x2e2_26_animating = false;
    }
  }

  if (!x2e2_25_dead && HealthInfo(mgr)->GetHP() <= 0.f) {
    x2e2_25_dead = true;
    SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None);
  }
}

void CScriptActor::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
  CActor::PreRender(mgr, frustum);

  if (xe4_30_outOfFrustum && TCastToConstPtr<CCinematicCamera>(mgr.GetCameraManager()->GetCurrentCamera(mgr))) {
    xe4_30_outOfFrustum = false;
  }

  if (!xe4_30_outOfFrustum && x2e2_29_processModelFlags) {
    if (x2e2_27_xrayAlphaEnabled) {
      const zeus::CColor col(1.f, x2dc_xrayAlpha);
      const CModelFlags xrayFlags(5, 0, 3, col);
      if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) {
        xb4_drawFlags = xrayFlags;
        x2e2_28_inXrayAlpha = true;
      } else if (x2e2_28_inXrayAlpha) {
        x2e2_28_inXrayAlpha = false;
        if (xb4_drawFlags == xrayFlags) {
          xb4_drawFlags = CModelFlags(0, 0, 3, zeus::skWhite);
        }
      }
    }

    if (x2e2_24_noThermalHotZ && xe6_27_thermalVisorFlags == 2) {
      if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::Thermal) {
        xb4_drawFlags.x2_flags &= ~3; // Disable Z test/update
      } else {
        xb4_drawFlags.x2_flags |= 3; // Enable Z test/update
      }
    }

    if (x2d8_shaderIdx != 0) {
      xb4_drawFlags.x1_matSetIdx = u8(x2d8_shaderIdx);
    }
  }

  if (mgr.GetObjectById(x2e0_triggerId) == nullptr) {
    x2e0_triggerId = kInvalidUniqueId;
  }
}

zeus::CAABox CScriptActor::GetSortingBounds(const CStateManager& mgr) const {
  if (x2e0_triggerId != kInvalidUniqueId) {
    const TCastToConstPtr<CScriptTrigger> trigger(mgr.GetObjectById(x2e0_triggerId));
    if (trigger) {
      return trigger->GetTriggerBoundsWR();
    }
  }

  return CActor::GetSortingBounds(mgr);
}

EWeaponCollisionResponseTypes CScriptActor::GetCollisionResponseType(const zeus::CVector3f& v1,
                                                                     const zeus::CVector3f& v2,
                                                                     const CWeaponMode& wMode,
                                                                     EProjectileAttrib w) const {
  const CDamageVulnerability* dVuln = GetDamageVulnerability();
  if (dVuln->GetVulnerability(wMode, false) == EVulnerability::Deflect) {
    const EDeflectType deflectType = dVuln->GetDeflectionType(wMode);
    if (deflectType < EDeflectType::Four && deflectType >= EDeflectType::One) {
      return EWeaponCollisionResponseTypes::Unknown15;
    }
  }
  return CActor::GetCollisionResponseType(v1, v2, wMode, w);
}

std::optional<zeus::CAABox> CScriptActor::GetTouchBounds() const {
  if (GetActive() && x68_material.HasMaterial(EMaterialTypes::Solid)) {
    return {CPhysicsActor::GetBoundingBox()};
  }
  return std::nullopt;
}

void CScriptActor::Touch(CActor&, CStateManager&) {
  // Empty
}
} // namespace urde
<commit_msg>CScriptActor: Remove unused printf code<commit_after>#include "Runtime/World/CScriptActor.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/CPlayerState.hpp"
#include "Runtime/Camera/CGameCamera.hpp"
#include "Runtime/Character/IAnimReader.hpp"
#include "Runtime/MP1/World/CActorContraption.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CDamageVulnerability.hpp"
#include "Runtime/World/CScriptColorModulate.hpp"
#include "Runtime/World/CScriptTrigger.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

#include <zeus/CEulerAngles.hpp>

namespace urde {

CScriptActor::CScriptActor(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                           CModelData&& mData, const zeus::CAABox& aabb, float mass, float zMomentum,
                           const CMaterialList& matList, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
                           const CActorParameters& actParms, bool looping, bool active, s32 shaderIdx, float xrayAlpha,
                           bool noThermalHotZ, bool castsShadow, bool scaleAdvancementDelta, bool materialFlag54)
: CPhysicsActor(uid, active, name, info, xf, std::move(mData), matList, aabb, SMoverData(mass), actParms, 0.3f, 0.1f)
, x258_initialHealth(hInfo)
, x260_currentHealth(hInfo)
, x268_damageVulnerability(dVuln)
, x2d0_fadeInTime(actParms.x5c_fadeInTime)
, x2d4_fadeOutTime(actParms.x60_fadeOutTime)
, x2d8_shaderIdx(shaderIdx)
, x2dc_xrayAlpha(xrayAlpha) {
  x2e2_24_noThermalHotZ = noThermalHotZ;
  x2e2_27_xrayAlphaEnabled = !zeus::close_enough(1.f, xrayAlpha);
  x2e2_29_processModelFlags = (x2e2_27_xrayAlphaEnabled || x2e2_24_noThermalHotZ || x2d8_shaderIdx != 0);
  x2e2_30_scaleAdvancementDelta = scaleAdvancementDelta;
  x2e2_31_materialFlag54 = materialFlag54;

  if (x64_modelData && (x64_modelData->HasAnimData() || x64_modelData->HasNormalModel()) && castsShadow) {
    CreateShadow(true);
  }

  if (x64_modelData && x64_modelData->HasAnimData()) {
    x64_modelData->EnableLooping(looping);
  }

  x150_momentum = zeus::CVector3f(0.f, 0.f, zMomentum);
}

void CScriptActor::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CScriptActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  switch (msg) {
  case EScriptObjectMessage::InitializedInArea:
    for (const SConnection& conn : x20_conns) {
      if (conn.x0_state != EScriptObjectState::InheritBounds || conn.x4_msg != EScriptObjectMessage::Activate) {
        continue;
      }

      const auto search = mgr.GetIdListForScript(conn.x8_objId);
      for (auto it = search.first; it != search.second; ++it) {
        if (TCastToConstPtr<CScriptTrigger>(mgr.GetObjectById(it->second))) {
          x2e0_triggerId = it->second;
          break;
        }
      }
    }

    if (x2e2_31_materialFlag54) {
      CActor::AddMaterial(EMaterialTypes::Unknown54, mgr);
    }
    break;
  case EScriptObjectMessage::Reset:
    x2e2_25_dead = false;
    x260_currentHealth = x258_initialHealth;
    break;
  case EScriptObjectMessage::Increment:
    if (!GetActive()) {
      mgr.SendScriptMsg(this, x8_uid, EScriptObjectMessage::Activate);
      CScriptColorModulate::FadeInHelper(mgr, x8_uid, x2d0_fadeInTime);
    }
    break;
  case EScriptObjectMessage::Decrement:
    CScriptColorModulate::FadeOutHelper(mgr, x8_uid, x2d4_fadeOutTime);
    break;
  default:
    break;
  }

  CActor::AcceptScriptMsg(msg, uid, mgr);
}

void CScriptActor::Think(float dt, CStateManager& mgr) {
  if (!GetActive()) {
    return;
  }

  if (HasModelData() && x64_modelData->HasAnimData()) {
    const bool timeRemaining = x64_modelData->GetAnimationData()->IsAnimTimeRemaining(dt - FLT_EPSILON, "Whole Body");
    const bool loop = x64_modelData->GetIsLoop();

    const SAdvancementDeltas deltas = CActor::UpdateAnimation(dt, mgr, true);

    if (timeRemaining || loop) {
      x2e2_26_animating = true;

      if (x2e2_30_scaleAdvancementDelta) {
        MoveToOR(x34_transform.rotate(x64_modelData->GetScale() * x34_transform.transposeRotate(deltas.x0_posDelta)),
                 dt);
      } else {
        MoveToOR(deltas.x0_posDelta, dt);
      }

      RotateToOR(deltas.xc_rotDelta, dt);
    }

    if (!timeRemaining && x2e2_26_animating && !loop) {
      SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None);
      x2e2_26_animating = false;
    }
  }

  if (!x2e2_25_dead && HealthInfo(mgr)->GetHP() <= 0.f) {
    x2e2_25_dead = true;
    SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None);
  }
}

void CScriptActor::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
  CActor::PreRender(mgr, frustum);

  if (xe4_30_outOfFrustum && TCastToConstPtr<CCinematicCamera>(mgr.GetCameraManager()->GetCurrentCamera(mgr))) {
    xe4_30_outOfFrustum = false;
  }

  if (!xe4_30_outOfFrustum && x2e2_29_processModelFlags) {
    if (x2e2_27_xrayAlphaEnabled) {
      const zeus::CColor col(1.f, x2dc_xrayAlpha);
      const CModelFlags xrayFlags(5, 0, 3, col);
      if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) {
        xb4_drawFlags = xrayFlags;
        x2e2_28_inXrayAlpha = true;
      } else if (x2e2_28_inXrayAlpha) {
        x2e2_28_inXrayAlpha = false;
        if (xb4_drawFlags == xrayFlags) {
          xb4_drawFlags = CModelFlags(0, 0, 3, zeus::skWhite);
        }
      }
    }

    if (x2e2_24_noThermalHotZ && xe6_27_thermalVisorFlags == 2) {
      if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::Thermal) {
        xb4_drawFlags.x2_flags &= ~3; // Disable Z test/update
      } else {
        xb4_drawFlags.x2_flags |= 3; // Enable Z test/update
      }
    }

    if (x2d8_shaderIdx != 0) {
      xb4_drawFlags.x1_matSetIdx = u8(x2d8_shaderIdx);
    }
  }

  if (mgr.GetObjectById(x2e0_triggerId) == nullptr) {
    x2e0_triggerId = kInvalidUniqueId;
  }
}

zeus::CAABox CScriptActor::GetSortingBounds(const CStateManager& mgr) const {
  if (x2e0_triggerId != kInvalidUniqueId) {
    const TCastToConstPtr<CScriptTrigger> trigger(mgr.GetObjectById(x2e0_triggerId));
    if (trigger) {
      return trigger->GetTriggerBoundsWR();
    }
  }

  return CActor::GetSortingBounds(mgr);
}

EWeaponCollisionResponseTypes CScriptActor::GetCollisionResponseType(const zeus::CVector3f& v1,
                                                                     const zeus::CVector3f& v2,
                                                                     const CWeaponMode& wMode,
                                                                     EProjectileAttrib w) const {
  const CDamageVulnerability* dVuln = GetDamageVulnerability();
  if (dVuln->GetVulnerability(wMode, false) == EVulnerability::Deflect) {
    const EDeflectType deflectType = dVuln->GetDeflectionType(wMode);
    if (deflectType < EDeflectType::Four && deflectType >= EDeflectType::One) {
      return EWeaponCollisionResponseTypes::Unknown15;
    }
  }
  return CActor::GetCollisionResponseType(v1, v2, wMode, w);
}

std::optional<zeus::CAABox> CScriptActor::GetTouchBounds() const {
  if (GetActive() && x68_material.HasMaterial(EMaterialTypes::Solid)) {
    return {CPhysicsActor::GetBoundingBox()};
  }
  return std::nullopt;
}

void CScriptActor::Touch(CActor&, CStateManager&) {
  // Empty
}
} // namespace urde
<|endoftext|>