<commit_before>#include <thread>

#include "reactor.h"

const std::string reactor::KEY_TIMER = "timer";

reactor::reactor(std::shared_ptr<zmq::context_t> context)
	: context_(context), async_handler_socket_(*context, zmq::socket_type::router),
	  unique_id("reactor_" + std::to_string((uintptr_t) this))
{
	async_handler_socket_.bind("inproc://" + unique_id);
}

void reactor::add_socket(const std::string &name, std::shared_ptr<socket_wrapper_base> socket)
{
	sockets_.emplace(name, socket);
}

void reactor::add_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<handler_wrapper>(*this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::add_async_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<asynchronous_handler_wrapper>(*context_, async_handler_socket_, *this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::send_message(const message_container &message)
{
	auto it = sockets_.find(message.key);

	// If there is a matching socket, send the message there. If not, let the reactor handle it
	if (it != std::end(sockets_)) {
		it->second->send_message(message);
	} else {
		process_message(message);
	}
}

void reactor::process_message(const message_container &message)
{
	auto range = handlers_.equal_range(message.key);

	for (auto it = range.first; it != range.second; ++it) {
		(*it->second)(message);
	}
}

void reactor::start_loop()
{
	std::vector<zmq::pollitem_t> pollitems;
	std::vector<std::string> pollitem_names;

	// Poll all registered sockets
	for (auto it : sockets_) {
		it.second->initialize();
		pollitems.push_back(it.second->get_pollitem());
		pollitem_names.push_back(it.first);
	}

	// Also poll the internal socket for asynchronous communication
	pollitems.push_back(
		zmq_pollitem_t{.socket = (void *) async_handler_socket_, .fd = 0, .events = ZMQ_POLLIN, .revents = 0});

	// Enter the poll loop
	while (true) {
		auto time_before_poll = std::chrono::system_clock::now();
		zmq::poll(pollitems, std::chrono::milliseconds(100));
		auto time_after_poll = std::chrono::system_clock::now();

		auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(time_after_poll - time_before_poll);

		size_t i = 0;
		for (auto item : pollitems) {
			if (item.revents & ZMQ_POLLIN) {
				message_container received_msg;
				sockets_.at(pollitem_names.at(i))->receive_message(received_msg);
				process_message(received_msg);
			}

			++i;
		}

		message_container timer_msg;
		timer_msg.key = KEY_TIMER;
		timer_msg.data.push_back(std::to_string(elapsed_time.count()));

		process_message(timer_msg);
	}
}

handler_wrapper::handler_wrapper(reactor &reactor_ref, std::shared_ptr<handler_interface> handler)
	: handler_(handler), reactor_(reactor_ref)
{
}

handler_wrapper::~handler_wrapper()
{
}

void handler_wrapper::operator()(const message_container &message)
{
	handler_->on_request(message, [this](const message_container &response) { reactor_.send_message(response); });
}

asynchronous_handler_wrapper::asynchronous_handler_wrapper(zmq::context_t &context,
	zmq::socket_t &async_handler_socket,
	reactor &reactor_ref,
	std::shared_ptr<handler_interface> handler)
	: handler_wrapper(reactor_ref, handler), reactor_socket_(async_handler_socket),
	  unique_id_(std::to_string((uintptr_t) this)), handler_thread_socket_(context, zmq::socket_type::dealer),
	  worker_([this]() { handler_thread(); })
{
}

asynchronous_handler_wrapper::~asynchronous_handler_wrapper()
{
	// Set a flag for the worker thread that indicates it can terminate
	running_.store(false);

	// Send a dummy message to wake the worker thread up
	reactor_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	reactor_socket_.send("TERMINATE", 10);

	// Join it
	worker_.join();
}

void asynchronous_handler_wrapper::operator()(const message_container &message)
{
	reactor_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	reactor_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	reactor_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		reactor_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}

void asynchronous_handler_wrapper::handler_thread()
{
	handler_thread_socket_.setsockopt(ZMQ_IDENTITY, unique_id_.data(), unique_id_.size());
	handler_thread_socket_.connect("inproc://" + reactor_.unique_id);
	running_.store(true);

	while (running_.load()) {
		message_container request;
		zmq::message_t message;

		handler_thread_socket_.recv(&message, 0);
		request.key = std::string(static_cast<char *>(message.data()), message.size());

		if (!message.more()) {
			continue;
		}

		handler_thread_socket_.recv(&message, 0);
		request.identity = std::string(static_cast<char *>(message.data()), message.size());

		while (message.more()) {
			handler_thread_socket_.recv(&message, 0);
			request.data.emplace_back(static_cast<char *>(message.data()), message.size());
		}

		handler_->on_request(request, [this](const message_container &response) { send_response(response); });
	}
}

void asynchronous_handler_wrapper::send_response(const message_container &message)
{
	handler_thread_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		handler_thread_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}
<commit_msg>fill in message key correctly<commit_after>#include <thread>

#include "reactor.h"

const std::string reactor::KEY_TIMER = "timer";

reactor::reactor(std::shared_ptr<zmq::context_t> context)
	: context_(context), async_handler_socket_(*context, zmq::socket_type::router),
	  unique_id("reactor_" + std::to_string((uintptr_t) this))
{
	async_handler_socket_.bind("inproc://" + unique_id);
}

void reactor::add_socket(const std::string &name, std::shared_ptr<socket_wrapper_base> socket)
{
	sockets_.emplace(name, socket);
}

void reactor::add_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<handler_wrapper>(*this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::add_async_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<asynchronous_handler_wrapper>(*context_, async_handler_socket_, *this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::send_message(const message_container &message)
{
	auto it = sockets_.find(message.key);

	// If there is a matching socket, send the message there. If not, let the reactor handle it
	if (it != std::end(sockets_)) {
		it->second->send_message(message);
	} else {
		process_message(message);
	}
}

void reactor::process_message(const message_container &message)
{
	auto range = handlers_.equal_range(message.key);

	for (auto it = range.first; it != range.second; ++it) {
		(*it->second)(message);
	}
}

void reactor::start_loop()
{
	std::vector<zmq::pollitem_t> pollitems;
	std::vector<std::string> pollitem_names;

	// Poll all registered sockets
	for (auto it : sockets_) {
		it.second->initialize();
		pollitems.push_back(it.second->get_pollitem());
		pollitem_names.push_back(it.first);
	}

	// Also poll the internal socket for asynchronous communication
	pollitems.push_back(
		zmq_pollitem_t{.socket = (void *) async_handler_socket_, .fd = 0, .events = ZMQ_POLLIN, .revents = 0});

	// Enter the poll loop
	while (true) {
		auto time_before_poll = std::chrono::system_clock::now();
		zmq::poll(pollitems, std::chrono::milliseconds(100));
		auto time_after_poll = std::chrono::system_clock::now();

		auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(time_after_poll - time_before_poll);

		size_t i = 0;
		for (auto item : pollitems) {
			if (item.revents & ZMQ_POLLIN) {
				message_container received_msg;
				received_msg.key = pollitem_names.at(i);
				sockets_.at(received_msg.key)->receive_message(received_msg);
				process_message(received_msg);
			}

			++i;
		}

		message_container timer_msg;
		timer_msg.key = KEY_TIMER;
		timer_msg.data.push_back(std::to_string(elapsed_time.count()));

		process_message(timer_msg);
	}
}

handler_wrapper::handler_wrapper(reactor &reactor_ref, std::shared_ptr<handler_interface> handler)
	: handler_(handler), reactor_(reactor_ref)
{
}

handler_wrapper::~handler_wrapper()
{
}

void handler_wrapper::operator()(const message_container &message)
{
	handler_->on_request(message, [this](const message_container &response) { reactor_.send_message(response); });
}

asynchronous_handler_wrapper::asynchronous_handler_wrapper(zmq::context_t &context,
	zmq::socket_t &async_handler_socket,
	reactor &reactor_ref,
	std::shared_ptr<handler_interface> handler)
	: handler_wrapper(reactor_ref, handler), reactor_socket_(async_handler_socket),
	  unique_id_(std::to_string((uintptr_t) this)), handler_thread_socket_(context, zmq::socket_type::dealer),
	  worker_([this]() { handler_thread(); })
{
}

asynchronous_handler_wrapper::~asynchronous_handler_wrapper()
{
	// Set a flag for the worker thread that indicates it can terminate
	running_.store(false);

	// Send a dummy message to wake the worker thread up
	reactor_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	reactor_socket_.send("TERMINATE", 10);

	// Join it
	worker_.join();
}

void asynchronous_handler_wrapper::operator()(const message_container &message)
{
	reactor_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	reactor_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	reactor_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		reactor_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}

void asynchronous_handler_wrapper::handler_thread()
{
	handler_thread_socket_.setsockopt(ZMQ_IDENTITY, unique_id_.data(), unique_id_.size());
	handler_thread_socket_.connect("inproc://" + reactor_.unique_id);
	running_.store(true);

	while (running_.load()) {
		message_container request;
		zmq::message_t message;

		handler_thread_socket_.recv(&message, 0);
		request.key = std::string(static_cast<char *>(message.data()), message.size());

		if (!message.more()) {
			continue;
		}

		handler_thread_socket_.recv(&message, 0);
		request.identity = std::string(static_cast<char *>(message.data()), message.size());

		while (message.more()) {
			handler_thread_socket_.recv(&message, 0);
			request.data.emplace_back(static_cast<char *>(message.data()), message.size());
		}

		handler_->on_request(request, [this](const message_container &response) { send_response(response); });
	}
}

void asynchronous_handler_wrapper::send_response(const message_container &message)
{
	handler_thread_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		handler_thread_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}
<|endoftext|>


<commit_before>#include "catch.hpp"
#include <iostream>
#include "Database_Creator.hpp"
#include "Database_Sorter.hpp"

person readPerson(std::string file_name, size_t index) {
	person result;
	std::ifstream file(file_name);
	for (size_t i = 0; i < index + 1; i++) {
		file >> result;
	}
	file.close();
	return result;
}
/*bool isALessThanB(char A, char B, bool is_capital) {
	std::string alphabet;
	if (is_capital) {
		alphabet = " АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	}
	else {
		alphabet = " абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
	}
	size_t A_i;
	size_t B_i;
	for (size_t i = 0; i < alphabet.size(); i++) {
		if (alphabet[i] == A) {
			A_i = i;
		}
		if (alphabet[i] == B) {
			B_i = i;
		}
	}
	return A_i < B_i;
}*/
bool isANotMoreThanB(person A, person B) {
	for (size_t i = 0; i < A.surname.length(); i++) {
		char A_char = A.surname[i];
		char B_char = (i < B.surname.length()) ? B.surname[i] : ' ';
		if (letterI(A.surname[i], i == 0) < letterI(B.surname[i], i == 0)) {
			return true;
		}
		else {
			if (A.surname[i] != B.surname[i]) {
				return false;
			}
		}
	}
	return true;
}

SCENARIO("Sort", "[s]") {
	//setlocale(LC_ALL, "ru_RU.utf8");
	std::ifstream ru("russian_letters.txt");
	for (size_t i = 0; i < 6; i++) {
		std::string str;
		ru >> str;
		russian_letters[i] = str[0];
	}
	ru.close();
	size_t n_persons = 2001;
	size_t RAM_amount = 10000;
	std::string names_file_name = "Names";
	std::string surnames_file_name = "Surnames";
	std::string database_file_name = "database.txt";
	std::string output_file_name = "sorted_database.txt";
	{
		Database_Creator database_creator(database_file_name, names_file_name, surnames_file_name, n_persons);
		Database_Sorter database_sorter(database_file_name, output_file_name, RAM_amount);
		size_t start = clock();
		database_sorter.sortDatabase();
		size_t result = clock() - start;
		std::cout << result << std::endl;
		system("pause");
	}

	for (size_t i = 0; i < 0; i++) {
		size_t person1_i = rand() % n_persons;
		size_t person2_i = person1_i + rand() % (n_persons - person1_i);
		person person1 = readPerson(output_file_name, person1_i);
		person person2 = readPerson(output_file_name, person2_i);
		REQUIRE(isANotMoreThanB(person1, person2));
	}

	/*std::string str = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	REQUIRE(letterI(str[1], true) == 2);
	REQUIRE(letterI(str[2], true) == 3);
	REQUIRE(letterI(str[3], true) == 4);
	REQUIRE(letterI(str[4], true) == 5);*/
}
<commit_msg>Update init.cpp<commit_after>#include "catch.hpp"
#include <iostream>
#include "Database_Creator.hpp"
#include "Database_Sorter.hpp"

person readPerson(std::string file_name, size_t index) {
	person result;
	std::ifstream file(file_name);
	for (size_t i = 0; i < index + 1; i++) {
		file >> result;
	}
	file.close();
	return result;
}
/*bool isALessThanB(char A, char B, bool is_capital) {
	std::string alphabet;
	if (is_capital) {
		alphabet = " АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	}
	else {
		alphabet = " абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
	}
	size_t A_i;
	size_t B_i;
	for (size_t i = 0; i < alphabet.size(); i++) {
		if (alphabet[i] == A) {
			A_i = i;
		}
		if (alphabet[i] == B) {
			B_i = i;
		}
	}
	return A_i < B_i;
}*/
bool isANotMoreThanB(person A, person B) {
	for (size_t i = 0; i < A.surname.length(); i++) {
		char A_char = A.surname[i];
		char B_char = (i < B.surname.length()) ? B.surname[i] : ' ';
		if (letterI(A.surname[i], i == 0) < letterI(B.surname[i], i == 0)) {
			return true;
		}
		else {
			if (A.surname[i] != B.surname[i]) {
				return false;
			}
		}
	}
	return true;
}

SCENARIO("Sort", "[s]") {
	//setlocale(LC_ALL, "ru_RU.utf8");
	std::ifstream ru("russian_letters.txt");
	for (size_t i = 0; i < 6; i++) {
		std::string str;
		ru >> str;
		russian_letters[i] = str[0];
	}
	ru.close();
	size_t n_persons = 2001;
	size_t RAM_amount = 10000;
	std::string names_file_name = "Names";
	std::string surnames_file_name = "Surnames";
	std::string database_file_name = "database.txt";
	std::string output_file_name = "sorted_database.txt";
	{
		Database_Creator database_creator(database_file_name, names_file_name, surnames_file_name, n_persons);
		Database_Sorter database_sorter(database_file_name, output_file_name, RAM_amount);
		size_t start = clock();
		database_sorter.sortDatabase();
		size_t result = clock() - start;
		std::cout << result << std::endl;
		system("pause");
	}

	for (size_t i = 0; i < 0; i++) {
		size_t person1_i = rand() % n_persons;
		size_t person2_i = person1_i + rand() % (n_persons - person1_i);
		person person1 = readPerson(output_file_name, person1_i);
		person person2 = readPerson(output_file_name, person2_i);
		REQUIRE(isANotMoreThanB(person1, person2));
	}

	/*std::string str = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	REQUIRE(letterI(str[1], true) == 2);
	REQUIRE(letterI(str[2], true) == 3);
	REQUIRE(letterI(str[3], true) == 4);
	REQUIRE(letterI(str[4], true) == 5);*/
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: fmexch.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: fs $ $Date: 2002-05-27 12:36:04 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SVX_FMEXCH_HXX
#define _SVX_FMEXCH_HXX

#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif

#ifndef _TRANSFER_HXX
#include <svtools/transfer.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
#include <com/sun/star/container/XNameContainer.hpp>
#endif
#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif

class FmFormShell;
class FmFormPage;
class SvLBoxEntry;

//========================================================================
// Exchange types
#define SVX_FM_FIELD_EXCH           String("SvxFormFieldExch",              sizeof("SvxFormFieldExch"))
#define SVX_FM_CONTROL_EXCH         String("SvxFormExplCtrlExch",           sizeof("SvxFormExplCtrlExch"))
#define SVX_FM_CONTROLS_AS_PATH     String("SvxFormControlsAsPathExchange", sizeof("SvxFormControlsAsPathExchange"))
#define SVX_FM_HIDDEN_CONTROLS      String("SvxFormHiddenControlsExchange", sizeof("SvxFormHiddenControlsExchange"))
#define SVX_FM_FILTER_FIELDS        String("SvxFilterFieldExchange",        sizeof("SvxFilterFieldExchange"))

//========================================================================
class SvTreeListBox;

//........................................................................
namespace svxform
{
//........................................................................

    //====================================================================

    DECLARE_STL_VECTOR( SvLBoxEntry*, ListBoxEntryArray );

    //====================================================================
    //= OLocalExchange
    //====================================================================
    class OLocalExchange : public TransferableHelper
    {
    private:
        Link                m_aClipboardListener;
        sal_Bool            m_bDragging         : 1;
        sal_Bool            m_bClipboardOwner   : 1;

    public:
        class GrantAccess
        {
            friend class OLocalExchangeHelper;
        };

    public:
        OLocalExchange( );

        sal_Bool    isDragging() const { return m_bDragging; }
        sal_Bool    isClipboardOwner() const { return m_bClipboardOwner; }

        void        startDrag( Window* pWindow, sal_Int8 nDragSourceActions, const GrantAccess& );
        void        copyToClipboard( Window* _pWindow, const GrantAccess& );

        void        setClipboardListener( const Link& _rListener ) { m_aClipboardListener = _rListener; }

        void        clear();

        static  sal_Bool    hasFormat( const DataFlavorExVector& _rFormats, sal_uInt32 _nFormatId );

    protected:
        // XClipboardOwner
        virtual void SAL_CALL lostOwnership( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& _rxClipboard, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& _rxTrans ) throw(::com::sun::star::uno::RuntimeException);

        // TransferableHelper
        virtual void        DragFinished( sal_Int8 nDropAction );
        virtual sal_Bool    GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor );

    private:
        void StartDrag( Window* pWindow, sal_Int8 nDragSourceActions, sal_Int32 nDragPointer = DND_POINTER_NONE, sal_Int32 nDragImage = DND_IMAGE_NONE )
        {   // don't allow this base class method to be called from outside
            TransferableHelper::StartDrag(pWindow, nDragSourceActions, nDragPointer, nDragImage);
        }
    };

    //====================================================================
    //= OLocalExchangeHelper
    //====================================================================
    /// a helper for navigator windows (SvTreeListBox'es) which allow DnD within themself
    class OLocalExchangeHelper
    {
    protected:
        Window*             m_pDragSource;
        OLocalExchange*     m_pTransferable;

    public:
        OLocalExchangeHelper( Window* _pDragSource );
        ~OLocalExchangeHelper();

        void        prepareDrag( );

        void        startDrag( sal_Int8 nDragSourceActions );
        void        copyToClipboard( ) const;

        inline  sal_Bool    isDragSource() const { return m_pTransferable && m_pTransferable->isDragging(); }
        inline  sal_Bool    isClipboardOwner() const { return m_pTransferable && m_pTransferable->isClipboardOwner(); }
        inline  sal_Bool    isDataExchangeActive( ) const { return isDragSource() || isClipboardOwner(); }

        void        setClipboardListener( const Link& _rListener ) { if ( m_pTransferable ) m_pTransferable->setClipboardListener( _rListener ); }

    protected:
        virtual OLocalExchange* createExchange() const = 0;

    protected:
        void implReset();
    };

    //====================================================================
    //= OControlTransferData
    //====================================================================
    class OControlTransferData
    {
    private:
        typedef ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< sal_uInt32 > > ControlPaths;

    private:
        DataFlavorExVector  m_aCurrentFormats;

    protected:
        ListBoxEntryArray   m_aSelectedEntries;
        ControlPaths        m_aControlPaths;
        ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > >
                            m_aHiddenControlModels;

        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                            m_xFormsRoot;       // the root of the forms collection where the entries we represent reside
                                                // this uniquely identifies the page and the document

        SvLBoxEntry*        m_pFocusEntry;

    protected:
        // updates m_aCurrentFormats with all formats we currently could supply
        void    updateFormats( );

    public:
        OControlTransferData( );

        // ctor to construct the data from an arbitrary Transferable (usually clipboard data)
        OControlTransferData(
            const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& _rxTransferable
        );

        inline const DataFlavorExVector&    GetDataFlavorExVector() const;

        void addSelectedEntry( SvLBoxEntry* _pEntry );
        void setFocusEntry( SvLBoxEntry* _pFocusEntry );

        void setFormsRoot(
            const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& _rxFormsRoot
            ) { m_xFormsRoot = _rxFormsRoot; }

        void buildPathFormat(SvTreeListBox* pTreeBox, SvLBoxEntry* pRoot);
            // baut aus m_aSelectedEntries m_aControlPaths auf
            // (es wird davon ausgegangen, dass die Eintraege in m_aSelectedEntries sortiert sind in Bezug auf die Nachbar-Beziehung)

        void buildListFromPath(SvTreeListBox* pTreeBox, SvLBoxEntry* pRoot);
            // der umgekehrte Weg : wirft alles aus m_aSelectedEntries weg und baut es mittels m_aControlPaths neu auf

        void addHiddenControlsFormat(const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > seqInterfaces);
            // fuegt ein SVX_FML_HIDDEN_CONTROLS-Format hinzu und merk sich dafuer die uebergebenen Interfaces
            // (es erfolgt KEINE Ueberpruefung, ob dadurch auch tatsaechlich nur hidden Controls bezeichnet werden, dass muss der
            // Aufrufer sicherstellen)

        SvLBoxEntry*                focused() const { return m_pFocusEntry; }
        const ListBoxEntryArray&    selected() const { return m_aSelectedEntries; }
        ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > >
                                    hiddenControls() const { return m_aHiddenControlModels; }

        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                                getFormsRoot() const { return m_xFormsRoot; }
    };

    //====================================================================
    inline const DataFlavorExVector& OControlTransferData::GetDataFlavorExVector() const
    {
        const_cast< OControlTransferData* >( this )->updateFormats( );
        return m_aCurrentFormats;
    }

    //====================================================================
    //= OControlExchange
    //====================================================================
    class OControlExchange : public OLocalExchange, public OControlTransferData
    {
    public:
        OControlExchange( );

    public:
        static sal_uInt32       getFieldExchangeFormatId( );
        static sal_uInt32       getControlPathFormatId( );
        static sal_uInt32       getHiddenControlModelsFormatId( );

        inline static sal_Bool  hasFieldExchangeFormat( const DataFlavorExVector& _rFormats );
        inline static sal_Bool  hasControlPathFormat( const DataFlavorExVector& _rFormats );
        inline static sal_Bool  hasHiddenControlModelsFormat( const DataFlavorExVector& _rFormats );

    protected:
        virtual sal_Bool    GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor );
        virtual void        AddSupportedFormats();
    };

    //====================================================================
    //= OControlExchangeHelper
    //====================================================================
    class OControlExchangeHelper : public OLocalExchangeHelper
    {
    public:
        OControlExchangeHelper(Window* _pDragSource) : OLocalExchangeHelper(_pDragSource) { }

        OControlExchange* operator->() const { return static_cast< OControlExchange* >( m_pTransferable ); }
        OControlExchange& operator*() const { return *static_cast< OControlExchange* >( m_pTransferable ); }

    protected:
        virtual OLocalExchange* createExchange() const;
    };

    //====================================================================
    //====================================================================
    inline sal_Bool OControlExchange::hasFieldExchangeFormat( const DataFlavorExVector& _rFormats )
    {
        return hasFormat( _rFormats, getFieldExchangeFormatId() );
    }

    inline sal_Bool OControlExchange::hasControlPathFormat( const DataFlavorExVector& _rFormats )
    {
        return hasFormat( _rFormats, getControlPathFormatId() );
    }

    inline sal_Bool OControlExchange::hasHiddenControlModelsFormat( const DataFlavorExVector& _rFormats )
    {
        return hasFormat( _rFormats, getHiddenControlModelsFormatId() );
    }

//........................................................................
}   // namespace svxform
//........................................................................

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.10.1634); FILE MERGED 2005/09/05 14:25:06 rt 1.10.1634.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fmexch.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 23:15:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SVX_FMEXCH_HXX
#define _SVX_FMEXCH_HXX

#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif

#ifndef _TRANSFER_HXX
#include <svtools/transfer.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
#include <com/sun/star/container/XNameContainer.hpp>
#endif
#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif

class FmFormShell;
class FmFormPage;
class SvLBoxEntry;

//========================================================================
// Exchange types
#define SVX_FM_FIELD_EXCH           String("SvxFormFieldExch",              sizeof("SvxFormFieldExch"))
#define SVX_FM_CONTROL_EXCH         String("SvxFormExplCtrlExch",           sizeof("SvxFormExplCtrlExch"))
#define SVX_FM_CONTROLS_AS_PATH     String("SvxFormControlsAsPathExchange", sizeof("SvxFormControlsAsPathExchange"))
#define SVX_FM_HIDDEN_CONTROLS      String("SvxFormHiddenControlsExchange", sizeof("SvxFormHiddenControlsExchange"))
#define SVX_FM_FILTER_FIELDS        String("SvxFilterFieldExchange",        sizeof("SvxFilterFieldExchange"))

//========================================================================
class SvTreeListBox;

//........................................................................
namespace svxform
{
//........................................................................

    //====================================================================

    DECLARE_STL_VECTOR( SvLBoxEntry*, ListBoxEntryArray );

    //====================================================================
    //= OLocalExchange
    //====================================================================
    class OLocalExchange : public TransferableHelper
    {
    private:
        Link                m_aClipboardListener;
        sal_Bool            m_bDragging         : 1;
        sal_Bool            m_bClipboardOwner   : 1;

    public:
        class GrantAccess
        {
            friend class OLocalExchangeHelper;
        };

    public:
        OLocalExchange( );

        sal_Bool    isDragging() const { return m_bDragging; }
        sal_Bool    isClipboardOwner() const { return m_bClipboardOwner; }

        void        startDrag( Window* pWindow, sal_Int8 nDragSourceActions, const GrantAccess& );
        void        copyToClipboard( Window* _pWindow, const GrantAccess& );

        void        setClipboardListener( const Link& _rListener ) { m_aClipboardListener = _rListener; }

        void        clear();

        static  sal_Bool    hasFormat( const DataFlavorExVector& _rFormats, sal_uInt32 _nFormatId );

    protected:
        // XClipboardOwner
        virtual void SAL_CALL lostOwnership( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& _rxClipboard, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& _rxTrans ) throw(::com::sun::star::uno::RuntimeException);

        // TransferableHelper
        virtual void        DragFinished( sal_Int8 nDropAction );
        virtual sal_Bool    GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor );

    private:
        void StartDrag( Window* pWindow, sal_Int8 nDragSourceActions, sal_Int32 nDragPointer = DND_POINTER_NONE, sal_Int32 nDragImage = DND_IMAGE_NONE )
        {   // don't allow this base class method to be called from outside
            TransferableHelper::StartDrag(pWindow, nDragSourceActions, nDragPointer, nDragImage);
        }
    };

    //====================================================================
    //= OLocalExchangeHelper
    //====================================================================
    /// a helper for navigator windows (SvTreeListBox'es) which allow DnD within themself
    class OLocalExchangeHelper
    {
    protected:
        Window*             m_pDragSource;
        OLocalExchange*     m_pTransferable;

    public:
        OLocalExchangeHelper( Window* _pDragSource );
        ~OLocalExchangeHelper();

        void        prepareDrag( );

        void        startDrag( sal_Int8 nDragSourceActions );
        void        copyToClipboard( ) const;

        inline  sal_Bool    isDragSource() const { return m_pTransferable && m_pTransferable->isDragging(); }
        inline  sal_Bool    isClipboardOwner() const { return m_pTransferable && m_pTransferable->isClipboardOwner(); }
        inline  sal_Bool    isDataExchangeActive( ) const { return isDragSource() || isClipboardOwner(); }

        void        setClipboardListener( const Link& _rListener ) { if ( m_pTransferable ) m_pTransferable->setClipboardListener( _rListener ); }

    protected:
        virtual OLocalExchange* createExchange() const = 0;

    protected:
        void implReset();
    };

    //====================================================================
    //= OControlTransferData
    //====================================================================
    class OControlTransferData
    {
    private:
        typedef ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< sal_uInt32 > > ControlPaths;

    private:
        DataFlavorExVector  m_aCurrentFormats;

    protected:
        ListBoxEntryArray   m_aSelectedEntries;
        ControlPaths        m_aControlPaths;
        ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > >
                            m_aHiddenControlModels;

        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                            m_xFormsRoot;       // the root of the forms collection where the entries we represent reside
                                                // this uniquely identifies the page and the document

        SvLBoxEntry*        m_pFocusEntry;

    protected:
        // updates m_aCurrentFormats with all formats we currently could supply
        void    updateFormats( );

    public:
        OControlTransferData( );

        // ctor to construct the data from an arbitrary Transferable (usually clipboard data)
        OControlTransferData(
            const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& _rxTransferable
        );

        inline const DataFlavorExVector&    GetDataFlavorExVector() const;

        void addSelectedEntry( SvLBoxEntry* _pEntry );
        void setFocusEntry( SvLBoxEntry* _pFocusEntry );

        void setFormsRoot(
            const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& _rxFormsRoot
            ) { m_xFormsRoot = _rxFormsRoot; }

        void buildPathFormat(SvTreeListBox* pTreeBox, SvLBoxEntry* pRoot);
            // baut aus m_aSelectedEntries m_aControlPaths auf
            // (es wird davon ausgegangen, dass die Eintraege in m_aSelectedEntries sortiert sind in Bezug auf die Nachbar-Beziehung)

        void buildListFromPath(SvTreeListBox* pTreeBox, SvLBoxEntry* pRoot);
            // der umgekehrte Weg : wirft alles aus m_aSelectedEntries weg und baut es mittels m_aControlPaths neu auf

        void addHiddenControlsFormat(const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > seqInterfaces);
            // fuegt ein SVX_FML_HIDDEN_CONTROLS-Format hinzu und merk sich dafuer die uebergebenen Interfaces
            // (es erfolgt KEINE Ueberpruefung, ob dadurch auch tatsaechlich nur hidden Controls bezeichnet werden, dass muss der
            // Aufrufer sicherstellen)

        SvLBoxEntry*                focused() const { return m_pFocusEntry; }
        const ListBoxEntryArray&    selected() const { return m_aSelectedEntries; }
        ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > >
                                    hiddenControls() const { return m_aHiddenControlModels; }

        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >
                                getFormsRoot() const { return m_xFormsRoot; }
    };

    //====================================================================
    inline const DataFlavorExVector& OControlTransferData::GetDataFlavorExVector() const
    {
        const_cast< OControlTransferData* >( this )->updateFormats( );
        return m_aCurrentFormats;
    }

    //====================================================================
    //= OControlExchange
    //====================================================================
    class OControlExchange : public OLocalExchange, public OControlTransferData
    {
    public:
        OControlExchange( );

    public:
        static sal_uInt32       getFieldExchangeFormatId( );
        static sal_uInt32       getControlPathFormatId( );
        static sal_uInt32       getHiddenControlModelsFormatId( );

        inline static sal_Bool  hasFieldExchangeFormat( const DataFlavorExVector& _rFormats );
        inline static sal_Bool  hasControlPathFormat( const DataFlavorExVector& _rFormats );
        inline static sal_Bool  hasHiddenControlModelsFormat( const DataFlavorExVector& _rFormats );

    protected:
        virtual sal_Bool    GetData( const ::com::sun::star::datatransfer::DataFlavor& rFlavor );
        virtual void        AddSupportedFormats();
    };

    //====================================================================
    //= OControlExchangeHelper
    //====================================================================
    class OControlExchangeHelper : public OLocalExchangeHelper
    {
    public:
        OControlExchangeHelper(Window* _pDragSource) : OLocalExchangeHelper(_pDragSource) { }

        OControlExchange* operator->() const { return static_cast< OControlExchange* >( m_pTransferable ); }
        OControlExchange& operator*() const { return *static_cast< OControlExchange* >( m_pTransferable ); }

    protected:
        virtual OLocalExchange* createExchange() const;
    };

    //====================================================================
    //====================================================================
    inline sal_Bool OControlExchange::hasFieldExchangeFormat( const DataFlavorExVector& _rFormats )
    {
        return hasFormat( _rFormats, getFieldExchangeFormatId() );
    }

    inline sal_Bool OControlExchange::hasControlPathFormat( const DataFlavorExVector& _rFormats )
    {
        return hasFormat( _rFormats, getControlPathFormatId() );
    }

    inline sal_Bool OControlExchange::hasHiddenControlModelsFormat( const DataFlavorExVector& _rFormats )
    {
        return hasFormat( _rFormats, getHiddenControlModelsFormatId() );
    }

//........................................................................
}   // namespace svxform
//........................................................................

#endif

<|endoftext|>


<commit_before>#include "lest.hpp"

#include "../twombly.hpp"
#define NO_SHOW

#include <iostream>

using namespace tw;

#define RED 2
#define GREEN 1
#define BLUE 0
#define ALPHA 3

int opencv_error_handler(int status, const char* func_name, const char* err_msg,
                   const char* file_name, int line, void*)
{
    return 0;
}

const lest::test drawing_test[] = {
    CASE ( "Mat3b drawing" ) {
        Mat3b im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec3b>(10, 10)[RED] == 255);
        EXPECT(im.at<Vec3b>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec3b>(10, 10)[BLUE] == 0);
    },

    CASE ( "Mat4b drawing" ) {
        Mat4b im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec4b>(10, 10)[RED] == 255);
        EXPECT(im.at<Vec4b>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec4b>(10, 10)[BLUE] == 0);
        EXPECT(im.at<Vec4b>(10, 10)[ALPHA] == 255);
    },

    CASE ( "Mat3w drawing" ) {
        Mat3w im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec3w>(10, 10)[RED] == 65535);
        EXPECT(im.at<Vec3w>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec3w>(10, 10)[BLUE] == 0);
    },

    CASE ( "Mat4w drawing" ) {
        Mat4w im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec4w>(10, 10)[RED] == 65535);
        EXPECT(im.at<Vec4w>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec4w>(10, 10)[BLUE] == 0);
        EXPECT(im.at<Vec4w>(10, 10)[ALPHA] == 65535);
    },

    CASE ( "Path" ) {
        Mat3b im(500, 500);
        auto d = draw(im);
        d.preserve(true);
        d.new_path();
        d.set_color(255, 255, 255);
        d.move_to(10, 10);
        d.line_to(490, 490);
        d.stroke();

        int pathid = d.active_path();

        EXPECT (d.total_vertices() == 2);

        double x, y;
        d.vertex(1, &x, &y);
        EXPECT(x == 490);
        EXPECT(y == 490);

        d.modify_vertex(1, 248, 249);
        d.vertex(1, &x, &y);
        EXPECT(x == 248);
        EXPECT(y == 249);

        d.new_path();
        EXPECT (d.active_path() != pathid);
        EXPECT (d.active_path() > pathid);

        d.new_path();
        d.line_width(2);
        d.ellipse(250, 250, 100, 100);
        d.stroke();

        d.active_path(pathid);
        d.stroke();
        d.preserve(false);

#ifndef NO_SHOW
        try{
            namedWindow("Path test");
            imshow("Path test", im);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE ( "Curve" ) {
        Mat3b im2(500, 500);
        im2.setTo(Scalar(255, 255, 255));
        auto d = draw(im2);

        d.set_color(255, 0, 0);
        d.move_to(100, 100);
        d.curve_to(400, 400, 100, 320);
        d.stroke();

#ifndef NO_SHOW
        try {
            namedWindow("Curve test");
            imshow("Curve test", im2);
            waitKey(0);
        } catch (std::exception &exc){

        }
#endif

        d.new_path();
        d.clear(255, 255, 255);
        d.set_color(0, 255, 0);
        d.move_to(100, 100);
        d.curve_to(400, 400, 150, 320);
        d.stroke();

#ifndef NO_SHOW
        try{
            imshow("Curve test", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE ( "Gradient" ) {
        Mat3w im2(500, 500);
        im2.setTo(Scalar(255, 255, 255));
        auto d = draw(im2);

        d.set_color(255, 0, 0);
        d.move_to(100, 100);
        d.curve_to(400, 400, 100, 320);
        d.stroke();

        d.new_path();
        d.ellipse(250, 250, 250, 250);

        Gradient<Color16> g;
        g.add_stop(Color16(255<<8, 0, 0, 127<<8));
        g.add_stop(Color16(0, 255<<8, 0, 127<<8));
        g.add_stop(Color16(0, 0, 255<<8, 127<<8));

        d.fill_gradient(g, 0, 300, gradient_type_y);
        EXPECT((im2.at<Scalar>(250, 250)[0] > 0));

#ifndef NO_SHOW
        try{
            imshow("Gradient test", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE("linear gradient many stops"){
        Mat3b im2(800, 800);
        auto d = draw(im2);

        Gradient<Color> g;

        for(int i = 0; i < 255; i++){
            g.add_stop(Color(i, 255-i, 255 * rand(), 255 * rand()));
        }

        d.rect(0, 0, 800, 800);
        d.fill_gradient(g, 0, 800, gradient_type_x);

#ifndef NO_SHOW
        try{
            imshow("Gradient test many stops", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE( "cairo-arc-infinite-loop"){
        Mat3b im2(8, 8);
        auto d = draw(im2);
        d.clear(255, 255, 255);

        d.move_to(0, 0);
        d.arc_to(0, 0, 1, 1024 / DBL_EPSILON * M_PI, 0);
        d.arc_to(0, 0, 1, 0, 1024 / DBL_EPSILON * M_PI);

        d.set_color(255, 0, 0);
        d.stroke();

    },

    CASE( "mask"){
        Mat3b im2(80, 80);
        memset(im2.data, 0,  80 * 80 * 3);

        auto d = draw(im2);

        d.antialias(false);
        d.alpha_mask_init();

        d.rect(0, 0, 80, 80);
        d.set_color(255, 0, 0, 255);
        for (int i = 20; i < 40; i++){
            for(int j = 20; j < 40; j++){
                d.alpha_mask_get(i, j) = 0;
            }
        }
        d.fill();

        imwrite("test1.jpg", im2);

        EXPECT((int)(im2.at<Vec3b>(30, 30)[2]) < 255);
    },

    CASE("Matrix rotation, scaling, translation, "){
        int PAT_WIDTH = 120, PAT_HEIGHT = 120, PAD = 2;
        Mat4b im2(((PAT_WIDTH*2) + 8), ((PAT_WIDTH*2) + 8));
        auto d = draw(im2);

        d.clear(0, 0, 0);

        d.translate(-PAT_WIDTH/2.0, -PAT_WIDTH/2.0);
        d.rotate(1.57079633);
        d.translate(PAT_WIDTH/2.0 + PAD, PAT_WIDTH/2.0-PAD);
        d.mtx.invert();

        d.scale(2, 2);

        d.set_color(255, 0, 255, 127);
        d.rect(PAT_WIDTH/6.0, PAT_HEIGHT/6.0, PAT_WIDTH/6.0 + PAT_WIDTH/4.0, PAT_WIDTH/6.0 + PAT_HEIGHT/4.0);
        d.fill();

        d.set_color (0, 255, 255, 127);
        d.rect(PAT_WIDTH/2.0, PAT_HEIGHT/2.0, PAT_WIDTH/2.0 + PAT_WIDTH/4.0,  PAT_WIDTH/2.0 + PAT_HEIGHT/4.0);
        d.fill();

        d.line_width(1);
        d.move_to(PAT_WIDTH/6.0, 0);
        d.line_to(0, 0);
        d.line_to(0, PAT_HEIGHT/6.0);
        d.set_color(255, 0, 0);
        d.stroke();

        d.move_to(PAT_WIDTH/6.0, PAT_HEIGHT);
        d.line_to(0, PAT_HEIGHT);
        d.line_to(0, 5 * PAT_HEIGHT/6.0);
        d.set_color(0, 0, 255, 255);
        d.stroke();

        d.move_to (5*PAT_WIDTH/6.0, 0);
        d.line_to (PAT_WIDTH, 0);
        d.line_to (PAT_WIDTH, PAT_HEIGHT/6.0);
        d.set_color (0, 0, 255, 255);
        d.stroke ();

        d.move_to (5*PAT_WIDTH/6.0, PAT_HEIGHT);
        d.line_to (PAT_WIDTH, PAT_HEIGHT);
        d.line_to (PAT_WIDTH, 5*PAT_HEIGHT/6.0);
        d.set_color (255, 255, 0, 255);
        d.stroke ();

        d.set_color (127, 127, 127);
        d.line_width (PAT_WIDTH/10.0);

        d.move_to (0,         PAT_HEIGHT/4.0);
        d.line_to (PAT_WIDTH, PAT_HEIGHT/4.0);
        d.stroke ();

        d.move_to (PAT_WIDTH/4.0,         0);
        d.line_to (PAT_WIDTH/4.0, PAT_WIDTH);
        d.stroke ();

#ifndef NO_SHOW
        try{
            imshow("Test Matrix", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    }
};

int main(int argc, char **argv){
    cv::redirectError(opencv_error_handler);
    lest::run(drawing_test, argc, argv);
}
<commit_msg>update tests for new alpha methods<commit_after>#include "lest.hpp"

#include "../twombly.hpp"
#define NO_SHOW

#include <iostream>

using namespace tw;

#define RED 2
#define GREEN 1
#define BLUE 0
#define ALPHA 3

int opencv_error_handler(int status, const char* func_name, const char* err_msg,
                   const char* file_name, int line, void*)
{
    return 0;
}

const lest::test drawing_test[] = {
    CASE ( "Mat3b drawing" ) {
        Mat3b im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec3b>(10, 10)[RED] == 255);
        EXPECT(im.at<Vec3b>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec3b>(10, 10)[BLUE] == 0);
    },

    CASE ( "Mat4b drawing" ) {
        Mat4b im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec4b>(10, 10)[RED] == 255);
        EXPECT(im.at<Vec4b>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec4b>(10, 10)[BLUE] == 0);
        EXPECT(im.at<Vec4b>(10, 10)[ALPHA] == 255);
    },

    CASE ( "Mat3w drawing" ) {
        Mat3w im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec3w>(10, 10)[RED] == 65535);
        EXPECT(im.at<Vec3w>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec3w>(10, 10)[BLUE] == 0);
    },

    CASE ( "Mat4w drawing" ) {
        Mat4w im(100, 100);
        auto d = draw(im);
        d.clear(255, 0, 0);
        EXPECT(im.at<Vec4w>(10, 10)[RED] == 65535);
        EXPECT(im.at<Vec4w>(10, 10)[GREEN] == 0);
        EXPECT(im.at<Vec4w>(10, 10)[BLUE] == 0);
        EXPECT(im.at<Vec4w>(10, 10)[ALPHA] == 65535);
    },

    CASE ( "Path" ) {
        Mat3b im(500, 500);
        auto d = draw(im);
        d.preserve(true);
        d.new_path();
        d.set_color(255, 255, 255);
        d.move_to(10, 10);
        d.line_to(490, 490);
        d.stroke();

        int pathid = d.active_path();

        EXPECT (d.total_vertices() == 2);

        double x, y;
        d.vertex(1, &x, &y);
        EXPECT(x == 490);
        EXPECT(y == 490);

        d.modify_vertex(1, 248, 249);
        d.vertex(1, &x, &y);
        EXPECT(x == 248);
        EXPECT(y == 249);

        d.new_path();
        EXPECT (d.active_path() != pathid);
        EXPECT (d.active_path() > pathid);

        d.new_path();
        d.line_width(2);
        d.ellipse(250, 250, 100, 100);
        d.stroke();

        d.active_path(pathid);
        d.stroke();
        d.preserve(false);

#ifndef NO_SHOW
        try{
            namedWindow("Path test");
            imshow("Path test", im);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE ( "Curve" ) {
        Mat3b im2(500, 500);
        im2.setTo(Scalar(255, 255, 255));
        auto d = draw(im2);

        d.set_color(255, 0, 0);
        d.move_to(100, 100);
        d.curve_to(400, 400, 100, 320);
        d.stroke();

#ifndef NO_SHOW
        try {
            namedWindow("Curve test");
            imshow("Curve test", im2);
            waitKey(0);
        } catch (std::exception &exc){

        }
#endif

        d.new_path();
        d.clear(255, 255, 255);
        d.set_color(0, 255, 0);
        d.move_to(100, 100);
        d.curve_to(400, 400, 150, 320);
        d.stroke();

#ifndef NO_SHOW
        try{
            imshow("Curve test", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE ( "Gradient" ) {
        Mat3w im2(500, 500);
        im2.setTo(Scalar(255, 255, 255));
        auto d = draw(im2);

        d.set_color(255, 0, 0);
        d.move_to(100, 100);
        d.curve_to(400, 400, 100, 320);
        d.stroke();

        d.new_path();
        d.ellipse(250, 250, 250, 250);

        Gradient<Color16> g;
        g.add_stop(Color16(255<<8, 0, 0, 127<<8));
        g.add_stop(Color16(0, 255<<8, 0, 127<<8));
        g.add_stop(Color16(0, 0, 255<<8, 127<<8));

        d.fill_gradient(g, 0, 300, gradient_type_y);
        EXPECT((im2.at<Scalar>(250, 250)[0] > 0));

#ifndef NO_SHOW
        try{
            imshow("Gradient test", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE("linear gradient many stops"){
        Mat3b im2(800, 800);
        auto d = draw(im2);

        Gradient<Color> g;

        for(int i = 0; i < 255; i++){
            g.add_stop(Color(i, 255-i, 255 * rand(), 255 * rand()));
        }

        d.rect(0, 0, 800, 800);
        d.fill_gradient(g, 0, 800, gradient_type_x);

#ifndef NO_SHOW
        try{
            imshow("Gradient test many stops", im2);
            waitKey(0);
            destroyAllWindows();
        } catch(std::exception &exc){

        }
#endif
    },

    CASE( "cairo-arc-infinite-loop"){
        Mat3b im2(8, 8);
        auto d = draw(im2);
        d.clear(255, 255, 255);

        d.move_to(0, 0);
        d.arc_to(0, 0, 1, 1024.0 / DBL_EPSILON * M_PI, 0);
        d.arc_to(0, 0, 1, 0, 1024.0 / DBL_EPSILON * M_PI);

        d.set_color(255, 0, 0);
        d.stroke();

        EXPECT((im2.at<Vec3b>(0, 0)[2] == 255 &&
                    im2.at<Vec3b>(0, 0)[2] > im2.at<Vec3b>(0, 0)[1] &&
                    im2.at<Vec3b>(0, 0)[2] > im2.at<Vec3b>(0, 0)[0]));
    },

    CASE( "mask"){
        Mat3b im2(80, 80);
        memset(im2.data, 0,  80 * 80 * 3);

        auto d = draw(im2);

        d.antialias(false);
        d.alpha_mask_init();

        d.rect(0, 0, 80, 80);
        d.set_color(255, 0, 0, 255);
        for (int i = 20; i < 40; i++){
            for(int j = 20; j < 40; j++){
                d.alpha_mask_set(i, j, 0);
            }
        }
        d.fill();
        EXPECT((im2.at<Vec3b>(30, 30)[2] == 0 &&
                    (im2.at<Vec3b>(30, 30)[1]) == 0 &&
                    (im2.at<Vec3b>(30, 30)[0]) == 0));
    }
};

int main(int argc, char **argv){
    cv::redirectError(opencv_error_handler);
    lest::run(drawing_test, argc, argv);
}
<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <RTcmix.h>
#include <ugens.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sndlibsupport.h>
#include "audio_devices.h"
#include "rtdefs.h"
#include <Option.h>

/* The syntax of rtoutput is expanded when using sndlib:

   rtoutput("filename" [, "header_type"] [, "data_format"])

   - "header_type" is one of:
        "aiff", "aifc", "wav", "next", "sun", or "ircam"

      The default is "aiff", since this is what most other unix
      programs can use (Notam software, Cecilia, etc.).

      "next" and "sun" (the familiar ".au" format) are synonyms.
      "ircam" is the older, non-hybrid BICSF format.
      (Note that sndlib can't write the hybrid EBICSF headers.)

      All formats are bigendian, except for "wav".

   - "data_format" is one of:
        "short"      16-bit linear
        "float"      32-bit floating point
        "normfloat"  32-bit floating point in range (mostly) from -1.0 to +1.0
        "16"         synonym for "short"
        "24"         24-bit linear, not yet supported in RTcmix

        The default is "short".

   NOTES:

     (1) The sampling rate and number of channels are specified in
         the call to rtsetparams.

     (2) If you ask for "aiff" and "float" (or "normfloat"),
         you'll get "aifc" format instead. This is because sndlib
         doesn't handle floats properly with AIFF format.

     (3) The case of the "header_type" and "data_format" arguments
         is not significant, nor is their order.

     (4) If you want to use floating point files in Snd, choose
         "normfloat" format. If you want to use them in Mxv, choose
         the "next" header type. Many programs don't read AIFC files,
         maybe because they assume these are always compressed.

   There are other possibilities with sndlib, but limiting the choices
   to those listed above makes for an easier Minc interface to rtoutput.
*/

/* CAUTION: Don't change these without thinking about constraints
            imposed by the various formats, and by sndlib and any
            programs (Mxv, Mix, Cecilia) that should be compatible.
*/
#define DEFAULT_HEADER_TYPE    MUS_AIFF
#define DEFAULT_DATA_FORMAT    MUS_BSHORT

#define CLOBBER_WARNING       \
"Specified output file already exists! \n\n\
Turn on \"clobber mode\" in your score to overwrite it.\n\
(Put \"set_option(\"clobber_on\")\" before call to rtoutput).\n"

typedef enum {
   INVALID_PARAM = 0,
   HEADER_TYPE,
   DATA_FORMAT,
   ENDIANNESS
} ParamType;

typedef struct {
   ParamType  type;
   int        value;
   char       arg[16];
} Param;

/* See description of these strings above.
   (Supporting endian request would be really confusing, because there
   are many constraints in the formats. The only thing it would buy
   us is the ability to specify little-endian AIFC linear formats.
   Not worth the trouble.)
*/
static Param param_list[] = {
   { HEADER_TYPE,  MUS_NEXT,     "next"      },
   { HEADER_TYPE,  MUS_NEXT,     "sun"       },
   { HEADER_TYPE,  MUS_AIFF,     "aiff"      },
   { HEADER_TYPE,  MUS_AIFC,     "aifc"      },
   { HEADER_TYPE,  MUS_RIFF,     "wav"       },
   { HEADER_TYPE,  MUS_IRCAM,    "ircam"     },
   { HEADER_TYPE,  MUS_RAW,      "raw"       },
   { DATA_FORMAT,  MUS_BSHORT,   "short"     },
   { DATA_FORMAT,  MUS_BFLOAT,   "float"     },
   { DATA_FORMAT,  MUS_BFLOAT,   "normfloat" },
   { DATA_FORMAT,  MUS_BSHORT,   "16"        },
   { DATA_FORMAT,  MUS_B24INT,   "24"        },
   { ENDIANNESS,   0,            "big"       },    /* not implemented */
   { ENDIANNESS,   1,            "little"    }
};
static int num_params = sizeof(param_list) / sizeof(Param);

/* for use in header_type_from_filename */
typedef struct {
   int   format;
   char  arg[8];
} Extension;

static Extension format_extension_list[] = {
   { MUS_NEXT,    "au"     },
   { MUS_NEXT,    "snd"    },
   { MUS_AIFF,    "aif"    },
   { MUS_AIFF,    "aiff"   },
   { MUS_AIFC,    "aifc"   },
   { MUS_RIFF,    "wav"    },
   { MUS_IRCAM,   "sf"     },
   { MUS_RAW,     "raw"    }
};
static int num_format_extensions = sizeof(format_extension_list)
                                                      / sizeof(Extension);

static int header_type_from_filename(char *);
static int parse_rtoutput_args(int, double []);

/* -------------------------------------------- header_type_from_filename --- */
static int
header_type_from_filename(char *fname)
{
   int   i, format = -1;
   char  *p;

   p = strrchr(fname, '.');
   if (p != NULL) {
      p++;     /* skip over '.' */
      for (i = 0; i < num_format_extensions; i++) {
         if (strcasecmp(format_extension_list[i].arg, p) == 0) {
            format = format_extension_list[i].format;
            break;
         }
      }
   }
   return format;
}

/* -------------------------------------------------- parse_rtoutput_args --- */
int
RTcmix::parse_rtoutput_args(int nargs, double pp[])
{
   int   anint, i, j, matched;
   int   normfloat_requested;
   char  *arg;

   if (nargs == 0) {
      rterror("rtoutput", "you didn't specify a file name!");
      return -1;
   }

   /* This is the ancient method of casting a double to a char ptr. */
   anint = (int)pp[0];
   rtoutsfname = (char *)anint;
   if (rtoutsfname == NULL)
   {
      rterror("rtoutput", "NULL file name!");
      return -1;
   }

   output_header_type = header_type_from_filename(rtoutsfname);
   if (output_header_type == -1)
      output_header_type = DEFAULT_HEADER_TYPE;
   output_data_format = DEFAULT_DATA_FORMAT;

   normfloat_requested = 0;

   for (i = 1; i < nargs; i++) {
      anint = (int)pp[i];
      arg = (char *)anint;

      matched = 0;
      for (j = 0; j < num_params; j++) {
         if (strcasecmp(param_list[j].arg, arg) == 0) {
            matched = 1;
            break;
         }
      }
      if (!matched) {
         rterror("rtoutput", "unrecognized argument \"%s\"", arg);
         return -1;
      }

      switch (param_list[j].type) {
         case HEADER_TYPE:
            output_header_type = param_list[j].value;
            break;
         case DATA_FORMAT:
            output_data_format = param_list[j].value;
            if (output_data_format == MUS_BFLOAT
                           && strcasecmp(param_list[j].arg, "normfloat") == 0)
               normfloat_requested = 1;
            break;
         case ENDIANNESS:  /* currently unused */
            break;
         default:
            break;
      }
   }

   /* Handle some special cases. */

   /* If "wav", make data format little-endian. */
   if (output_header_type == MUS_RIFF) {
      switch (output_data_format) {
         case MUS_BSHORT:
            output_data_format = MUS_LSHORT;
            break;
         case MUS_B24INT:
            output_data_format = MUS_L24INT;
            break;
         case MUS_BFLOAT:
            output_data_format = MUS_LFLOAT;
            break;
      }
   }

   /* If AIFF, use AIFC only if explicitly requested, or if
      the data format is float.
   */
   if (output_header_type == MUS_AIFF && output_data_format == MUS_BFLOAT)
      output_header_type = MUS_AIFC;

   /* If writing to a float file, decide whether to normalize the
      samples, i.e., to divide them all by 32768 so as to make the
      normal range fall between -1.0 and +1.0. This is what Snd
      and sndlib like to see, but it's not the old cmix way.
   */
   if (normfloat_requested)
      normalize_output_floats = 1;

   is_float_format = IS_FLOAT_FORMAT(output_data_format);

#ifdef ALLBUG
   fprintf(stderr, "name: %s, head: %d, data: %d, norm: %d\n",
                   rtoutsfname, output_header_type, output_data_format,
                   normalize_output_floats);
#endif

   return 0;
}

/* ------------------------------------------------------------- rtoutput --- */
/* This routine is used in the Minc score to open up a file for
   writing by RT instruments.  pp[0] is a pointer to the soundfile
   name, disguised as a double by the crafty Minc.  (p[] is passed in
   just for fun.)  Optional string arguments follow the filename,
   and parse_rtoutput_args processes these. See the comment at the
   top of this file for the meaning of these arguments.

   If "clobber" mode is on, we delete an existing file with the
   specified file name, creating a header according to what
   parse_rtoutput_args determines.

   Returns -1.0 if a file is already open for writing. Dies if there
   is any other error.
*/
double
RTcmix::rtoutput(float p[], int n_args, double pp[])
{
   int         error;
   struct stat statbuf;

   if (rtfileit == 1) {
      rterror("rtoutput", "A soundfile is already open for writing...");
      return -1;
   }

   /* flag set to -1 until we reach end of function.  This way, if anything
      fails along the way, we leave this set as we want it.
   */
   rtfileit = -1;

   if (SR == 0) {
      die("rtoutput", "You must call rtsetparams before rtoutput.");
      return -1;
   }

   error = parse_rtoutput_args(n_args, pp);
   if (error)
      return -1;          /* already reported in parse_rtoutput_args */

   error = stat(rtoutsfname, &statbuf);

   if (error) {
      if (errno == ENOENT) {
         ;              /* File doesn't exist -- no problem */
      }
      else {
         rterror("rtoutput", "Error accessing file \"%s\": %s",
                                                rtoutsfname, strerror(errno));
         return -1;  /* was exit() */
      }
   }
   else {               /* File exists; find out whether we can clobber it */
      if (!get_bool_option(kOptionClobber)) {
         rterror("rtoutput", "\n%s", CLOBBER_WARNING);
         return -1;
      }
      else {
         /* make sure it's a regular file */
         if (!S_ISREG(statbuf.st_mode)) {
            rterror("rtoutput", "\"%s\" isn't a regular file; won't clobber it",
                                                                 rtoutsfname);
            return -1;
         }
      }
   }

   AudioDevice *dev;
   if ((dev = create_audio_file_device(audioDevice,
				   				rtoutsfname, output_header_type,
                                output_data_format, NCHANS, SR,
                                normalize_output_floats,
                                get_bool_option(kOptionCheckPeaks))) == NULL)
      return -1;  /* failed! */

   audioDevice = dev;

   rtfileit = 1;  /* here we finally set this to 1 */

   return 1;
}

<commit_msg>Protection against overwriting your .sco file<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <RTcmix.h>
#include <ugens.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sndlibsupport.h>
#include "audio_devices.h"
#include "rtdefs.h"
#include <Option.h>

/* The syntax of rtoutput is expanded when using sndlib:

   rtoutput("filename" [, "header_type"] [, "data_format"])

   - "header_type" is one of:
        "aiff", "aifc", "wav", "next", "sun", or "ircam"

      The default is "aiff", since this is what most other unix
      programs can use (Notam software, Cecilia, etc.).

      "next" and "sun" (the familiar ".au" format) are synonyms.
      "ircam" is the older, non-hybrid BICSF format.
      (Note that sndlib can't write the hybrid EBICSF headers.)

      All formats are bigendian, except for "wav".

   - "data_format" is one of:
        "short"      16-bit linear
        "float"      32-bit floating point
        "normfloat"  32-bit floating point in range (mostly) from -1.0 to +1.0
        "16"         synonym for "short"
        "24"         24-bit linear, not yet supported in RTcmix

        The default is "short".

   NOTES:

     (1) The sampling rate and number of channels are specified in
         the call to rtsetparams.

     (2) If you ask for "aiff" and "float" (or "normfloat"),
         you'll get "aifc" format instead. This is because sndlib
         doesn't handle floats properly with AIFF format.

     (3) The case of the "header_type" and "data_format" arguments
         is not significant, nor is their order.

     (4) If you want to use floating point files in Snd, choose
         "normfloat" format. If you want to use them in Mxv, choose
         the "next" header type. Many programs don't read AIFC files,
         maybe because they assume these are always compressed.

   There are other possibilities with sndlib, but limiting the choices
   to those listed above makes for an easier Minc interface to rtoutput.
*/

/* CAUTION: Don't change these without thinking about constraints
            imposed by the various formats, and by sndlib and any
            programs (Mxv, Mix, Cecilia) that should be compatible.
*/
#define DEFAULT_HEADER_TYPE    MUS_AIFF
#define DEFAULT_DATA_FORMAT    MUS_BSHORT

#define CLOBBER_WARNING       \
"Specified output file already exists! \n\n\
Turn on \"clobber mode\" in your score to overwrite it.\n\
(Put \"set_option(\"clobber_on\")\" before call to rtoutput).\n"

typedef enum {
   INVALID_PARAM = 0,
   HEADER_TYPE,
   DATA_FORMAT,
   ENDIANNESS
} ParamType;

typedef struct {
   ParamType  type;
   int        value;
   char       arg[16];
} Param;

/* See description of these strings above.
   (Supporting endian request would be really confusing, because there
   are many constraints in the formats. The only thing it would buy
   us is the ability to specify little-endian AIFC linear formats.
   Not worth the trouble.)
*/
static Param param_list[] = {
   { HEADER_TYPE,  MUS_NEXT,     "next"      },
   { HEADER_TYPE,  MUS_NEXT,     "sun"       },
   { HEADER_TYPE,  MUS_AIFF,     "aiff"      },
   { HEADER_TYPE,  MUS_AIFC,     "aifc"      },
   { HEADER_TYPE,  MUS_RIFF,     "wav"       },
   { HEADER_TYPE,  MUS_IRCAM,    "ircam"     },
   { HEADER_TYPE,  MUS_RAW,      "raw"       },
   { DATA_FORMAT,  MUS_BSHORT,   "short"     },
   { DATA_FORMAT,  MUS_BFLOAT,   "float"     },
   { DATA_FORMAT,  MUS_BFLOAT,   "normfloat" },
   { DATA_FORMAT,  MUS_BSHORT,   "16"        },
   { DATA_FORMAT,  MUS_B24INT,   "24"        },
   { ENDIANNESS,   0,            "big"       },    /* not implemented */
   { ENDIANNESS,   1,            "little"    }
};
static int num_params = sizeof(param_list) / sizeof(Param);

/* for use in header_type_from_filename */
typedef struct {
   int   format;
   char  arg[8];
} Extension;

static Extension format_extension_list[] = {
   { MUS_NEXT,    "au"     },
   { MUS_NEXT,    "snd"    },
   { MUS_AIFF,    "aif"    },
   { MUS_AIFF,    "aiff"   },
   { MUS_AIFC,    "aifc"   },
   { MUS_RIFF,    "wav"    },
   { MUS_IRCAM,   "sf"     },
   { MUS_RAW,     "raw"    }
};
static int num_format_extensions = sizeof(format_extension_list)
                                                      / sizeof(Extension);

static int header_type_from_filename(char *);
static int parse_rtoutput_args(int, double []);

/* -------------------------------------------- header_type_from_filename --- */
static int
header_type_from_filename(char *fname)
{
   int   i, format = -2;
   char  *p;

   p = strrchr(fname, '.');
   if (p != NULL) {
      p++;     /* skip over '.' */
      if (strcasecmp(p, "sco") == 0)
         return die("rtoutput", "You asked to overwrite a \".sco\" file!");
      for (i = 0; i < num_format_extensions; i++) {
         if (strcasecmp(format_extension_list[i].arg, p) == 0) {
            format = format_extension_list[i].format;
            break;
         }
      }
   }
   return format;
}

/* -------------------------------------------------- parse_rtoutput_args --- */
int
RTcmix::parse_rtoutput_args(int nargs, double pp[])
{
   int   anint, i, j, matched;
   int   normfloat_requested;
   char  *arg;

   if (nargs == 0) {
      rterror("rtoutput", "you didn't specify a file name!");
      return -1;
   }

   /* This is the ancient method of casting a double to a char ptr. */
   anint = (int)pp[0];
   rtoutsfname = (char *)anint;
   if (rtoutsfname == NULL)
   {
      rterror("rtoutput", "NULL file name!");
      return -1;
   }

   output_header_type = header_type_from_filename(rtoutsfname);
   if (output_header_type == -1)
      return -1;
   if (output_header_type == -2)
      output_header_type = DEFAULT_HEADER_TYPE;
   output_data_format = DEFAULT_DATA_FORMAT;

   normfloat_requested = 0;

   for (i = 1; i < nargs; i++) {
      anint = (int)pp[i];
      arg = (char *)anint;

      matched = 0;
      for (j = 0; j < num_params; j++) {
         if (strcasecmp(param_list[j].arg, arg) == 0) {
            matched = 1;
            break;
         }
      }
      if (!matched) {
         rterror("rtoutput", "unrecognized argument \"%s\"", arg);
         return -1;
      }

      switch (param_list[j].type) {
         case HEADER_TYPE:
            output_header_type = param_list[j].value;
            break;
         case DATA_FORMAT:
            output_data_format = param_list[j].value;
            if (output_data_format == MUS_BFLOAT
                           && strcasecmp(param_list[j].arg, "normfloat") == 0)
               normfloat_requested = 1;
            break;
         case ENDIANNESS:  /* currently unused */
            break;
         default:
            break;
      }
   }

   /* Handle some special cases. */

   /* If "wav", make data format little-endian. */
   if (output_header_type == MUS_RIFF) {
      switch (output_data_format) {
         case MUS_BSHORT:
            output_data_format = MUS_LSHORT;
            break;
         case MUS_B24INT:
            output_data_format = MUS_L24INT;
            break;
         case MUS_BFLOAT:
            output_data_format = MUS_LFLOAT;
            break;
      }
   }

   /* If AIFF, use AIFC only if explicitly requested, or if
      the data format is float.
   */
   if (output_header_type == MUS_AIFF && output_data_format == MUS_BFLOAT)
      output_header_type = MUS_AIFC;

   /* If writing to a float file, decide whether to normalize the
      samples, i.e., to divide them all by 32768 so as to make the
      normal range fall between -1.0 and +1.0. This is what Snd
      and sndlib like to see, but it's not the old cmix way.
   */
   if (normfloat_requested)
      normalize_output_floats = 1;

   is_float_format = IS_FLOAT_FORMAT(output_data_format);

#ifdef ALLBUG
   fprintf(stderr, "name: %s, head: %d, data: %d, norm: %d\n",
                   rtoutsfname, output_header_type, output_data_format,
                   normalize_output_floats);
#endif

   return 0;
}

/* ------------------------------------------------------------- rtoutput --- */
/* This routine is used in the Minc score to open up a file for
   writing by RT instruments.  pp[0] is a pointer to the soundfile
   name, disguised as a double by the crafty Minc.  (p[] is passed in
   just for fun.)  Optional string arguments follow the filename,
   and parse_rtoutput_args processes these. See the comment at the
   top of this file for the meaning of these arguments.

   If "clobber" mode is on, we delete an existing file with the
   specified file name, creating a header according to what
   parse_rtoutput_args determines.

   Returns -1.0 if a file is already open for writing. Dies if there
   is any other error.
*/
double
RTcmix::rtoutput(float p[], int n_args, double pp[])
{
   int         error;
   struct stat statbuf;

   if (rtfileit == 1) {
      rterror("rtoutput", "A soundfile is already open for writing...");
      return -1;
   }

   /* flag set to -1 until we reach end of function.  This way, if anything
      fails along the way, we leave this set as we want it.
   */
   rtfileit = -1;

   if (SR == 0) {
      die("rtoutput", "You must call rtsetparams before rtoutput.");
      return -1;
   }

   error = parse_rtoutput_args(n_args, pp);
   if (error)
      return -1;          /* already reported in parse_rtoutput_args */

   error = stat(rtoutsfname, &statbuf);

   if (error) {
      if (errno == ENOENT) {
         ;              /* File doesn't exist -- no problem */
      }
      else {
         rterror("rtoutput", "Error accessing file \"%s\": %s",
                                                rtoutsfname, strerror(errno));
         return -1;  /* was exit() */
      }
   }
   else {               /* File exists; find out whether we can clobber it */
      if (!get_bool_option(kOptionClobber)) {
         rterror("rtoutput", "\n%s", CLOBBER_WARNING);
         return -1;
      }
      else {
         /* make sure it's a regular file */
         if (!S_ISREG(statbuf.st_mode)) {
            rterror("rtoutput", "\"%s\" isn't a regular file; won't clobber it",
                                                                 rtoutsfname);
            return -1;
         }
      }
   }

   AudioDevice *dev;
   if ((dev = create_audio_file_device(audioDevice,
				   				rtoutsfname, output_header_type,
                                output_data_format, NCHANS, SR,
                                normalize_output_floats,
                                get_bool_option(kOptionCheckPeaks))) == NULL)
      return -1;  /* failed! */

   audioDevice = dev;

   rtfileit = 1;  /* here we finally set this to 1 */

   return 1;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "script/standard.h"

#include "script/script.h"
#include "util.h"

#include <boost/foreach.hpp>

using namespace std;

typedef vector<unsigned char> valtype;

const char* GetTxnOutputType(txnouttype t)
{
    switch (t)
    {
    case TX_NONSTANDARD: return "nonstandard";
    case TX_PUBKEY: return "pubkey";
    case TX_PUBKEYHASH: return "pubkeyhash";
    case TX_SCRIPTHASH: return "scripthash";
    case TX_MULTISIG: return "multisig";
    case TX_NULL_DATA: return "nulldata";
    }
    return NULL;
}

//
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
//
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
{
    // Templates
    static multimap<txnouttype, CScript> mTemplates;
    if (mTemplates.empty())
    {
        // Standard tx, sender provides pubkey, receiver adds signature
        mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));

        // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
        mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));

        // Sender provides N pubkeys, receivers provides M signatures
        mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));

        // Empty, provably prunable, data-carrying output
        if (GetBoolArg("-datacarrier", true))
            mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
        mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
    }

    // Shortcut for pay-to-script-hash, which are more constrained than the other types:
    // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
    if (scriptPubKey.IsPayToScriptHash())
    {
        typeRet = TX_SCRIPTHASH;
        vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
        vSolutionsRet.push_back(hashBytes);
        return true;
    }

    // Scan templates
    const CScript& script1 = scriptPubKey;
    BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
    {
        const CScript& script2 = tplate.second;
        vSolutionsRet.clear();

        opcodetype opcode1, opcode2;
        vector<unsigned char> vch1, vch2;

        // Compare
        CScript::const_iterator pc1 = script1.begin();
        CScript::const_iterator pc2 = script2.begin();
        while (true)
        {
            if (pc1 == script1.end() && pc2 == script2.end())
            {
                // Found a match
                typeRet = tplate.first;
                if (typeRet == TX_MULTISIG)
                {
                    // Additional checks for TX_MULTISIG:
                    unsigned char m = vSolutionsRet.front()[0];
                    unsigned char n = vSolutionsRet.back()[0];
                    if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
                        return false;
                }
                return true;
            }
            if (!script1.GetOp(pc1, opcode1, vch1))
                break;
            if (!script2.GetOp(pc2, opcode2, vch2))
                break;

            // Template matching opcodes:
            if (opcode2 == OP_PUBKEYS)
            {
                while (vch1.size() >= 33 && vch1.size() <= 65)
                {
                    vSolutionsRet.push_back(vch1);
                    if (!script1.GetOp(pc1, opcode1, vch1))
                        break;
                }
                if (!script2.GetOp(pc2, opcode2, vch2))
                    break;
                // Normal situation is to fall through
                // to other if/else statements
            }

            if (opcode2 == OP_PUBKEY)
            {
                if (vch1.size() < 33 || vch1.size() > 65)
                    break;
                vSolutionsRet.push_back(vch1);
            }
            else if (opcode2 == OP_PUBKEYHASH)
            {
                if (vch1.size() != sizeof(uint160))
                    break;
                vSolutionsRet.push_back(vch1);
            }
            else if (opcode2 == OP_SMALLINTEGER)
            {   // Single-byte small integer pushed onto vSolutions
                if (opcode1 == OP_0 ||
                    (opcode1 >= OP_1 && opcode1 <= OP_16))
                {
                    char n = (char)CScript::DecodeOP_N(opcode1);
                    vSolutionsRet.push_back(valtype(1, n));
                }
                else
                    break;
            }
            else if (opcode2 == OP_SMALLDATA)
            {
                // small pushdata, <= MAX_OP_RETURN_RELAY bytes
                if (vch1.size() > MAX_OP_RETURN_RELAY)
                    break;
            }
            else if (opcode1 != opcode2 || vch1 != vch2)
            {
                // Others must match exactly
                break;
            }
        }
    }

    vSolutionsRet.clear();
    typeRet = TX_NONSTANDARD;
    return false;
}

int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
{
    switch (t)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        return -1;
    case TX_PUBKEY:
        return 1;
    case TX_PUBKEYHASH:
        return 2;
    case TX_MULTISIG:
        if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
            return -1;
        return vSolutions[0][0] + 1;
    case TX_SCRIPTHASH:
        return 1; // doesn't include args needed by the script
    }
    return -1;
}

bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
    vector<valtype> vSolutions;
    if (!Solver(scriptPubKey, whichType, vSolutions))
        return false;

    if (whichType == TX_MULTISIG)
    {
        unsigned char m = vSolutions.front()[0];
        unsigned char n = vSolutions.back()[0];
        // Support up to x-of-3 multisig txns as standard
        if (n < 1 || n > 3)
            return false;
        if (m < 1 || m > n)
            return false;
    }

    return whichType != TX_NONSTANDARD;
}

bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
    vector<valtype> vSolutions;
    txnouttype whichType;
    if (!Solver(scriptPubKey, whichType, vSolutions))
        return false;

    if (whichType == TX_PUBKEY)
    {
        addressRet = CPubKey(vSolutions[0]).GetID();
        return true;
    }
    else if (whichType == TX_PUBKEYHASH)
    {
        addressRet = CKeyID(uint160(vSolutions[0]));
        return true;
    }
    else if (whichType == TX_SCRIPTHASH)
    {
        addressRet = CScriptID(uint160(vSolutions[0]));
        return true;
    }
    // Multisig txns have more than one address...
    return false;
}

bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
{
    addressRet.clear();
    typeRet = TX_NONSTANDARD;
    vector<valtype> vSolutions;
    if (!Solver(scriptPubKey, typeRet, vSolutions))
        return false;
    if (typeRet == TX_NULL_DATA){
        // This is data, not addresses
        return false;
    }

    if (typeRet == TX_MULTISIG)
    {
        nRequiredRet = vSolutions.front()[0];
        for (unsigned int i = 1; i < vSolutions.size()-1; i++)
        {
            CTxDestination address = CPubKey(vSolutions[i]).GetID();
            addressRet.push_back(address);
        }
    }
    else
    {
        nRequiredRet = 1;
        CTxDestination address;
        if (!ExtractDestination(scriptPubKey, address))
           return false;
        addressRet.push_back(address);
    }

    return true;
}

namespace
{
class CScriptVisitor : public boost::static_visitor<bool>
{
private:
    CScript *script;
public:
    CScriptVisitor(CScript *scriptin) { script = scriptin; }

    bool operator()(const CNoDestination &dest) const {
        script->clear();
        return false;
    }

    bool operator()(const CKeyID &keyID) const {
        script->clear();
        *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
        return true;
    }

    bool operator()(const CScriptID &scriptID) const {
        script->clear();
        *script << OP_HASH160 << scriptID << OP_EQUAL;
        return true;
    }
};
}

CScript GetScriptForDestination(const CTxDestination& dest)
{
    CScript script;

    boost::apply_visitor(CScriptVisitor(&script), dest);
    return script;
}

CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
{
    CScript script;

    script << CScript::EncodeOP_N(nRequired);
    BOOST_FOREACH(const CPubKey& key, keys)
        script << key;
    script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
    return script;
}
<commit_msg>Don't return an address for invalid pubkeys<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "script/standard.h"

#include "script/script.h"
#include "util.h"

#include <boost/foreach.hpp>

using namespace std;

typedef vector<unsigned char> valtype;

const char* GetTxnOutputType(txnouttype t)
{
    switch (t)
    {
    case TX_NONSTANDARD: return "nonstandard";
    case TX_PUBKEY: return "pubkey";
    case TX_PUBKEYHASH: return "pubkeyhash";
    case TX_SCRIPTHASH: return "scripthash";
    case TX_MULTISIG: return "multisig";
    case TX_NULL_DATA: return "nulldata";
    }
    return NULL;
}

//
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
//
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
{
    // Templates
    static multimap<txnouttype, CScript> mTemplates;
    if (mTemplates.empty())
    {
        // Standard tx, sender provides pubkey, receiver adds signature
        mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));

        // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
        mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));

        // Sender provides N pubkeys, receivers provides M signatures
        mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));

        // Empty, provably prunable, data-carrying output
        if (GetBoolArg("-datacarrier", true))
            mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
        mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
    }

    // Shortcut for pay-to-script-hash, which are more constrained than the other types:
    // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
    if (scriptPubKey.IsPayToScriptHash())
    {
        typeRet = TX_SCRIPTHASH;
        vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
        vSolutionsRet.push_back(hashBytes);
        return true;
    }

    // Scan templates
    const CScript& script1 = scriptPubKey;
    BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
    {
        const CScript& script2 = tplate.second;
        vSolutionsRet.clear();

        opcodetype opcode1, opcode2;
        vector<unsigned char> vch1, vch2;

        // Compare
        CScript::const_iterator pc1 = script1.begin();
        CScript::const_iterator pc2 = script2.begin();
        while (true)
        {
            if (pc1 == script1.end() && pc2 == script2.end())
            {
                // Found a match
                typeRet = tplate.first;
                if (typeRet == TX_MULTISIG)
                {
                    // Additional checks for TX_MULTISIG:
                    unsigned char m = vSolutionsRet.front()[0];
                    unsigned char n = vSolutionsRet.back()[0];
                    if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
                        return false;
                }
                return true;
            }
            if (!script1.GetOp(pc1, opcode1, vch1))
                break;
            if (!script2.GetOp(pc2, opcode2, vch2))
                break;

            // Template matching opcodes:
            if (opcode2 == OP_PUBKEYS)
            {
                while (vch1.size() >= 33 && vch1.size() <= 65)
                {
                    vSolutionsRet.push_back(vch1);
                    if (!script1.GetOp(pc1, opcode1, vch1))
                        break;
                }
                if (!script2.GetOp(pc2, opcode2, vch2))
                    break;
                // Normal situation is to fall through
                // to other if/else statements
            }

            if (opcode2 == OP_PUBKEY)
            {
                if (vch1.size() < 33 || vch1.size() > 65)
                    break;
                vSolutionsRet.push_back(vch1);
            }
            else if (opcode2 == OP_PUBKEYHASH)
            {
                if (vch1.size() != sizeof(uint160))
                    break;
                vSolutionsRet.push_back(vch1);
            }
            else if (opcode2 == OP_SMALLINTEGER)
            {   // Single-byte small integer pushed onto vSolutions
                if (opcode1 == OP_0 ||
                    (opcode1 >= OP_1 && opcode1 <= OP_16))
                {
                    char n = (char)CScript::DecodeOP_N(opcode1);
                    vSolutionsRet.push_back(valtype(1, n));
                }
                else
                    break;
            }
            else if (opcode2 == OP_SMALLDATA)
            {
                // small pushdata, <= MAX_OP_RETURN_RELAY bytes
                if (vch1.size() > MAX_OP_RETURN_RELAY)
                    break;
            }
            else if (opcode1 != opcode2 || vch1 != vch2)
            {
                // Others must match exactly
                break;
            }
        }
    }

    vSolutionsRet.clear();
    typeRet = TX_NONSTANDARD;
    return false;
}

int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
{
    switch (t)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        return -1;
    case TX_PUBKEY:
        return 1;
    case TX_PUBKEYHASH:
        return 2;
    case TX_MULTISIG:
        if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
            return -1;
        return vSolutions[0][0] + 1;
    case TX_SCRIPTHASH:
        return 1; // doesn't include args needed by the script
    }
    return -1;
}

bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
    vector<valtype> vSolutions;
    if (!Solver(scriptPubKey, whichType, vSolutions))
        return false;

    if (whichType == TX_MULTISIG)
    {
        unsigned char m = vSolutions.front()[0];
        unsigned char n = vSolutions.back()[0];
        // Support up to x-of-3 multisig txns as standard
        if (n < 1 || n > 3)
            return false;
        if (m < 1 || m > n)
            return false;
    }

    return whichType != TX_NONSTANDARD;
}

bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
    vector<valtype> vSolutions;
    txnouttype whichType;
    if (!Solver(scriptPubKey, whichType, vSolutions))
        return false;

    if (whichType == TX_PUBKEY)
    {
        CPubKey pubKey(vSolutions[0]);
        if (!pubKey.IsValid())
            return false;

        addressRet = pubKey.GetID();
        return true;
    }
    else if (whichType == TX_PUBKEYHASH)
    {
        addressRet = CKeyID(uint160(vSolutions[0]));
        return true;
    }
    else if (whichType == TX_SCRIPTHASH)
    {
        addressRet = CScriptID(uint160(vSolutions[0]));
        return true;
    }
    // Multisig txns have more than one address...
    return false;
}

bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
{
    addressRet.clear();
    typeRet = TX_NONSTANDARD;
    vector<valtype> vSolutions;
    if (!Solver(scriptPubKey, typeRet, vSolutions))
        return false;
    if (typeRet == TX_NULL_DATA){
        // This is data, not addresses
        return false;
    }

    if (typeRet == TX_MULTISIG)
    {
        nRequiredRet = vSolutions.front()[0];
        for (unsigned int i = 1; i < vSolutions.size()-1; i++)
        {
            CPubKey pubKey(vSolutions[i]);
            if (!pubKey.IsValid())
                continue;

            CTxDestination address = pubKey.GetID();
            addressRet.push_back(address);
        }

        if (addressRet.empty())
            return false;
    }
    else
    {
        nRequiredRet = 1;
        CTxDestination address;
        if (!ExtractDestination(scriptPubKey, address))
           return false;
        addressRet.push_back(address);
    }

    return true;
}

namespace
{
class CScriptVisitor : public boost::static_visitor<bool>
{
private:
    CScript *script;
public:
    CScriptVisitor(CScript *scriptin) { script = scriptin; }

    bool operator()(const CNoDestination &dest) const {
        script->clear();
        return false;
    }

    bool operator()(const CKeyID &keyID) const {
        script->clear();
        *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
        return true;
    }

    bool operator()(const CScriptID &scriptID) const {
        script->clear();
        *script << OP_HASH160 << scriptID << OP_EQUAL;
        return true;
    }
};
}

CScript GetScriptForDestination(const CTxDestination& dest)
{
    CScript script;

    boost::apply_visitor(CScriptVisitor(&script), dest);
    return script;
}

CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
{
    CScript script;

    script << CScript::EncodeOP_N(nRequired);
    BOOST_FOREACH(const CPubKey& key, keys)
        script << key;
    script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
    return script;
}
<|endoftext|>