<commit_before>#include "TorrentFileParser.h"
#include <iostream>
#include <filesystem>
#include "SHA.h"

#define TPARSER_LOG(x) WRITE_LOG(LogTypeFileParser, x)

using namespace mtt;

bool generateInfoHash(BencodeParser& parsed, TorrentFileInfo&);
void loadTorrentFileInfo(BencodeParser& parsed, TorrentFileInfo&);
TorrentInfo parseTorrentInfo(const BencodeParser::Object* info);

TorrentFileInfo TorrentFileParser::parse(const uint8_t* data, size_t length)
{
	TorrentFileInfo out;
	BencodeParser parser;

	if (!parser.parse(data, length))
		return out;

	loadTorrentFileInfo(parser, out);
	generateInfoHash(parser, out);

	return out;
}

TorrentFileInfo TorrentFileParser::parseFile(const char* filename)
{
	TorrentFileInfo out;

	size_t maxSize = 10 * 1024 * 1024;
	std::filesystem::path dir(filename);

	if (!std::filesystem::exists(dir) || std::filesystem::file_size(dir) > maxSize)
	{
		TPARSER_LOG("Invalid torrent file " << filename);
		return out;
	}

	std::ifstream file(filename, std::ios_base::binary);

	if (!file.good())
	{
		TPARSER_LOG("Failed to open torrent file " << filename);
		return out;
	}

	DataBuffer buffer((
		std::istreambuf_iterator<char>(file)),
		(std::istreambuf_iterator<char>()));

	return parse(buffer.data(), buffer.size());
}

static uint32_t getPieceIndex(size_t pos, size_t pieceSize)
{
	size_t p = 0;

	while (pieceSize + p*pieceSize < pos)
	{
		p++;
	}

	return static_cast<uint32_t>(p);
}

void loadTorrentFileInfo(BencodeParser& parser, TorrentFileInfo& fileInfo)
{
	auto root = parser.getRoot();

	if (root && root->isMap())
	{
		if (auto announce = root->getTxtItem("announce"))
			fileInfo.announce = std::string(announce->data, announce->size);

		if (auto list = root->getListItem("announce-list"))
		{
			auto announce = list->getFirstItem();

			while (announce)
			{
				if (announce->isList())
				{
					auto a = announce->getFirstItem();

					while (a)
					{
						if (a->isText())
							fileInfo.announceList.push_back(std::string(a->info.data, a->info.size));

						a = a->getNextSibling();
					}
				}

				announce = announce->getNextSibling();
			}
		}
		else if (!fileInfo.announce.empty())
			fileInfo.announceList.push_back(fileInfo.announce);

		if (auto info = root->getDictItem("info"))
		{
			fileInfo.info = parseTorrentInfo(info);
		}
	}
}

bool generateInfoHash(BencodeParser& parser, TorrentFileInfo& fileInfo)
{
	const char* infoStart = nullptr;
	const char* infoEnd = nullptr;
	auto dict = parser.getRoot();

	if (dict)
	{
		auto it = dict->getFirstItem();

		while (it)
		{
			if (it->isText("info", 4))
			{
				infoStart = it->info.data + 4;

				auto infod = it->getNextSibling();

				if (infod->isMap())
				{
					auto pieces = infod->getTxtItem("pieces");

					if (pieces)
						infoEnd = pieces->data + pieces->size + 1;
				}

				it = nullptr;
			}
			else
				it = it->getNextSibling();
		}
	}

	if (infoStart && infoEnd)
	{
		SHA1((const unsigned char*)infoStart, infoEnd - infoStart, (unsigned char*)&fileInfo.info.hash[0]);

		return true;
	}
	else
		return false;
}

mtt::TorrentInfo mtt::TorrentFileParser::parseTorrentInfo(const uint8_t* data, size_t length)
{
	BencodeParser parser;

	if (parser.parse(data, length))
	{
		auto info = ::parseTorrentInfo(parser.getRoot());

		auto infoStart = (const char*)data;
		auto infoEnd = (const char*)data + length;

		SHA1((const unsigned char*)infoStart, infoEnd - infoStart, (unsigned char*)&info.hash[0]);

		return info;
	}
	else
		return mtt::TorrentInfo();
}

mtt::TorrentInfo parseTorrentInfo(const BencodeParser::Object* infoDictionary)
{
	mtt::TorrentInfo info;

	info.pieceSize = infoDictionary->getInt("piece length");

	auto piecesHash = infoDictionary->getTxtItem("pieces");

	if (piecesHash && piecesHash->size % 20 == 0)
	{
		PieceInfo temp;
		auto end = piecesHash->data + piecesHash->size;

		for (auto it = piecesHash->data; it != end; it += 20)
		{
			memcpy(temp.hash, it, 20);
			info.pieces.push_back(temp);
		}
	}

	if (auto files = infoDictionary->getListItem("files"))
	{
		info.name = infoDictionary->getTxt("name");

		size_t sizeSum = 0;

		auto file = files->getFirstItem();
		while(file)
		{
			std::vector<std::string> path;
			path.push_back(info.name);

			auto pathList = file->getListItem("path");
			auto pathItem = pathList->getFirstItem();
			while (pathItem)
			{
				path.push_back(pathItem->getTxt());
				pathItem = pathItem->getNextSibling();
			}

			size_t size = file->getBigInt("length");
			auto startId = getPieceIndex(sizeSum, info.pieceSize);
			auto startPos = sizeSum % info.pieceSize;
			sizeSum += size;
			auto endId = getPieceIndex(sizeSum, info.pieceSize);
			auto endPos = sizeSum % info.pieceSize;

			info.files.push_back({ path,  size, startId, (uint32_t)startPos, endId, (uint32_t)endPos });
			file = file->getNextSibling();
		}

		info.fullSize = sizeSum;
	}
	else
	{
		size_t size = infoDictionary->getBigInt("length");
		auto endPos = size % info.pieceSize;
		info.name = infoDictionary->getTxt("name");
		info.files.push_back({ { info.name }, size, 0, 0, static_cast<uint32_t>(info.pieces.size() - 1), (uint32_t)endPos });

		info.fullSize = size;
	}

	if (!info.files.empty())
	{
		info.lastPieceIndex = info.files.back().endPieceIndex;
		info.lastPieceSize = info.files.back().endPiecePos;
		info.lastPieceLastBlockIndex = (info.lastPieceSize - 1) / BlockRequestMaxSize;
		info.lastPieceLastBlockSize = info.lastPieceSize - (info.lastPieceLastBlockIndex * BlockRequestMaxSize);
	}

	auto piecesCount = info.pieces.size();
	auto addExpected = piecesCount % 8 > 0 ? 1 : 0; //8 pieces in byte
	info.expectedBitfieldSize = piecesCount / 8 + addExpected;

	return info;
}
<commit_msg>fix files ending with aligned piece size<commit_after>#include "TorrentFileParser.h"
#include <iostream>
#include <filesystem>
#include "SHA.h"

#define TPARSER_LOG(x) WRITE_LOG(LogTypeFileParser, x)

using namespace mtt;

bool generateInfoHash(BencodeParser& parsed, TorrentFileInfo&);
void loadTorrentFileInfo(BencodeParser& parsed, TorrentFileInfo&);
TorrentInfo parseTorrentInfo(const BencodeParser::Object* info);

TorrentFileInfo TorrentFileParser::parse(const uint8_t* data, size_t length)
{
	TorrentFileInfo out;
	BencodeParser parser;

	if (!parser.parse(data, length))
		return out;

	loadTorrentFileInfo(parser, out);
	generateInfoHash(parser, out);

	return out;
}

TorrentFileInfo TorrentFileParser::parseFile(const char* filename)
{
	TorrentFileInfo out;

	size_t maxSize = 10 * 1024 * 1024;
	std::filesystem::path dir(filename);

	if (!std::filesystem::exists(dir) || std::filesystem::file_size(dir) > maxSize)
	{
		TPARSER_LOG("Invalid torrent file " << filename);
		return out;
	}

	std::ifstream file(filename, std::ios_base::binary);

	if (!file.good())
	{
		TPARSER_LOG("Failed to open torrent file " << filename);
		return out;
	}

	DataBuffer buffer((
		std::istreambuf_iterator<char>(file)),
		(std::istreambuf_iterator<char>()));

	return parse(buffer.data(), buffer.size());
}

static uint32_t getPieceIndex(size_t pos, size_t pieceSize)
{
	size_t p = 0;

	while (pieceSize + p*pieceSize < pos)
	{
		p++;
	}

	return static_cast<uint32_t>(p);
}

void loadTorrentFileInfo(BencodeParser& parser, TorrentFileInfo& fileInfo)
{
	auto root = parser.getRoot();

	if (root && root->isMap())
	{
		if (auto announce = root->getTxtItem("announce"))
			fileInfo.announce = std::string(announce->data, announce->size);

		if (auto list = root->getListItem("announce-list"))
		{
			auto announce = list->getFirstItem();

			while (announce)
			{
				if (announce->isList())
				{
					auto a = announce->getFirstItem();

					while (a)
					{
						if (a->isText())
							fileInfo.announceList.push_back(std::string(a->info.data, a->info.size));

						a = a->getNextSibling();
					}
				}

				announce = announce->getNextSibling();
			}
		}
		else if (!fileInfo.announce.empty())
			fileInfo.announceList.push_back(fileInfo.announce);

		if (auto info = root->getDictItem("info"))
		{
			fileInfo.info = parseTorrentInfo(info);
		}
	}
}

bool generateInfoHash(BencodeParser& parser, TorrentFileInfo& fileInfo)
{
	const char* infoStart = nullptr;
	const char* infoEnd = nullptr;
	auto dict = parser.getRoot();

	if (dict)
	{
		auto it = dict->getFirstItem();

		while (it)
		{
			if (it->isText("info", 4))
			{
				infoStart = it->info.data + 4;

				auto infod = it->getNextSibling();

				if (infod->isMap())
				{
					auto pieces = infod->getTxtItem("pieces");

					if (pieces)
						infoEnd = pieces->data + pieces->size + 1;
				}

				it = nullptr;
			}
			else
				it = it->getNextSibling();
		}
	}

	if (infoStart && infoEnd)
	{
		SHA1((const unsigned char*)infoStart, infoEnd - infoStart, (unsigned char*)&fileInfo.info.hash[0]);

		return true;
	}
	else
		return false;
}

mtt::TorrentInfo mtt::TorrentFileParser::parseTorrentInfo(const uint8_t* data, size_t length)
{
	BencodeParser parser;

	if (parser.parse(data, length))
	{
		auto info = ::parseTorrentInfo(parser.getRoot());

		auto infoStart = (const char*)data;
		auto infoEnd = (const char*)data + length;

		SHA1((const unsigned char*)infoStart, infoEnd - infoStart, (unsigned char*)&info.hash[0]);

		return info;
	}
	else
		return mtt::TorrentInfo();
}

mtt::TorrentInfo parseTorrentInfo(const BencodeParser::Object* infoDictionary)
{
	mtt::TorrentInfo info;

	info.pieceSize = infoDictionary->getInt("piece length");

	auto piecesHash = infoDictionary->getTxtItem("pieces");

	if (piecesHash && piecesHash->size % 20 == 0)
	{
		PieceInfo temp;
		auto end = piecesHash->data + piecesHash->size;

		for (auto it = piecesHash->data; it != end; it += 20)
		{
			memcpy(temp.hash, it, 20);
			info.pieces.push_back(temp);
		}
	}

	if (auto files = infoDictionary->getListItem("files"))
	{
		info.name = infoDictionary->getTxt("name");

		size_t sizeSum = 0;

		auto file = files->getFirstItem();
		while(file)
		{
			std::vector<std::string> path;
			path.push_back(info.name);

			auto pathList = file->getListItem("path");
			auto pathItem = pathList->getFirstItem();
			while (pathItem)
			{
				path.push_back(pathItem->getTxt());
				pathItem = pathItem->getNextSibling();
			}

			size_t size = file->getBigInt("length");
			auto startId = getPieceIndex(sizeSum, info.pieceSize);
			auto startPos = sizeSum % info.pieceSize;
			sizeSum += size;
			auto endId = getPieceIndex(sizeSum, info.pieceSize);
			auto endPos = sizeSum % info.pieceSize;

			info.files.push_back({ path,  size, startId, (uint32_t)startPos, endId, (uint32_t)endPos });
			file = file->getNextSibling();
		}

		info.fullSize = sizeSum;
	}
	else
	{
		size_t size = infoDictionary->getBigInt("length");
		auto endPos = size % info.pieceSize;
		info.name = infoDictionary->getTxt("name");
		info.files.push_back({ { info.name }, size, 0, 0, static_cast<uint32_t>(info.pieces.size() - 1), (uint32_t)(endPos ? endPos : info.pieceSize) });

		info.fullSize = size;
	}

	if (!info.files.empty())
	{
		info.lastPieceIndex = info.files.back().endPieceIndex;
		info.lastPieceSize = info.files.back().endPiecePos;
		info.lastPieceLastBlockIndex = (info.lastPieceSize - 1) / BlockRequestMaxSize;
		info.lastPieceLastBlockSize = info.lastPieceSize - (info.lastPieceLastBlockIndex * BlockRequestMaxSize);
	}

	auto piecesCount = info.pieces.size();
	auto addExpected = piecesCount % 8 > 0 ? 1 : 0; //8 pieces in byte
	info.expectedBitfieldSize = piecesCount / 8 + addExpected;

	return info;
}
<|endoftext|>


<commit_before>// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include "config.h"

#include <cppunit/TextTestRunner.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/extensions/HelperMacros.h>

//#define DODS_DEBUG 1

#include "D4Group.h"

#include "Byte.h"
#include "Int64.h"

#include "XMLWriter.h"
#include "debug.h"

#include "testFile.h"
#include "test_config.h"

using namespace CppUnit;
using namespace std;
using namespace libdap;

class D4GroupTest: public TestFixture {
private:
    XMLWriter *xml;
    D4Group *root, *named;

public:
    D4GroupTest() {
    }

    ~D4GroupTest() {
    }

    void setUp() {
        root = new D4Group("");
        named = new D4Group("test");
        xml = new XMLWriter;
    }

    void tearDown() {
        delete xml;
        delete root;
        delete named;
    }

    void load_group_with_scalars(D4Group *g) {
        g->add_var_nocopy(new Byte("b"));
        g->add_var_nocopy(new Int64("i64"));
    }

    void load_group_with_stuff(D4Group *g) {
        g->dims()->add_dim_nocopy(new D4Dimension("lat", 1024));
        g->dims()->add_dim_nocopy(new D4Dimension("lon", 1024));
        g->dims()->add_dim_nocopy(new D4Dimension("time"));

        D4EnumDef *color_values = new D4EnumDef("colors", dods_byte_c);
        color_values->add_value("red", 1);
        color_values->add_value("green", 2);
        color_values->add_value("blue", 3);
        g->enum_defs()->add_enum_nocopy(color_values);

        g->get_attr_table().append_attr("test", "Int16", "1");
    }

    // An empty D4Group object prints nothing; the XMLWriter class adds
    // a xml doc preface.
    void test_print_empty() {
        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_empty.xml");
        DBG(cerr << "test_print_empty: doc: " << doc << endl);
        DBG(cerr << "test_print_empty: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_named_empty() {
        named->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_named_empty.xml");
        DBG(cerr << "test_print_named_empty: doc: " << doc << endl);
        DBG(cerr << "test_print_named_empty: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_with_vars() {
        load_group_with_scalars(root);

        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_with_scalars.xml");
        DBG(cerr << "test_print_with_vars: doc: " << doc << endl);
        DBG(cerr << "test_print_with_vars: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_named_with_vars() {
        load_group_with_scalars(named);

        named->print_dap4(*xml);

        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_named_with_scalars.xml");
        DBG(cerr << "test_print_named_with_vars: doc: " << doc << endl);
        DBG(cerr << "test_print_named_with_vars: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_with_vars_and_stuff() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_with_scalars_and_stuff.xml");
        DBG(cerr << "test_print_with_vars_and_stuff: doc: " << doc << endl);
        DBG(cerr << "test_print_with_vars_and_stuff: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_named_with_vars_and_stuff() {
        load_group_with_scalars(named);
        load_group_with_stuff(named);

        named->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_named_with_scalars_and_stuff.xml");
        DBG(cerr << "test_print_named_with_vars_and_stuff: doc: " << doc << endl);
        DBG(cerr << "test_print_named_with_vars_and_stuff: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_everything() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        D4Group *child = new D4Group("child");
        load_group_with_scalars(child);
        load_group_with_stuff(child);
        root->add_group(child);

        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_everything.xml");
        DBG(cerr << "test_print_with_vars_and_stuff: doc: " << doc << endl);
        DBG(cerr << "test_print_with_vars_and_stuff: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_copy_ctor() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        D4Group *child = new D4Group("child");
        load_group_with_scalars(child);
        load_group_with_stuff(child);
        root->add_group(child);

        D4Group lhs(*root);

        lhs.print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_everything.xml");
        DBG(cerr << "test_print_copy_ctor: doc: " << doc << endl);
        DBG(cerr << "test_print_copy_ctor: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_assignment() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        D4Group *child = new D4Group("child");
        load_group_with_scalars(child);
        load_group_with_stuff(child);
        root->add_group(child);

        D4Group lhs = *root;

        lhs.print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_everything.xml");
        DBG(cerr << "test_print_assignment: doc: " << doc << endl);
        DBG(cerr << "test_print_assignment: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    CPPUNIT_TEST_SUITE( D4GroupTest );

        CPPUNIT_TEST(test_print_empty);
        CPPUNIT_TEST(test_print_named_empty);
        CPPUNIT_TEST(test_print_with_vars);
        CPPUNIT_TEST(test_print_named_with_vars);

        CPPUNIT_TEST(test_print_with_vars_and_stuff);

        CPPUNIT_TEST(test_print_named_with_vars_and_stuff);
        CPPUNIT_TEST(test_print_everything);

        CPPUNIT_TEST(test_print_copy_ctor);
        CPPUNIT_TEST(test_print_assignment);

    CPPUNIT_TEST_SUITE_END();
};

CPPUNIT_TEST_SUITE_REGISTRATION(D4GroupTest);

int main(int, char**) {
    CppUnit::TextTestRunner runner;
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());

    bool wasSuccessful = runner.run("", false);

    return wasSuccessful ? 0 : 1;
}

<commit_msg>Fixed memory leaks in the D4Group unit tests<commit_after>// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include "config.h"

#include <cppunit/TextTestRunner.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/extensions/HelperMacros.h>

//#define DODS_DEBUG 1

#include "D4Group.h"

#include "Byte.h"
#include "Int64.h"

#include "XMLWriter.h"
#include "debug.h"

#include "testFile.h"
#include "test_config.h"

using namespace CppUnit;
using namespace std;
using namespace libdap;

class D4GroupTest: public TestFixture {
private:
    XMLWriter *xml;
    D4Group *root, *named;

public:
    D4GroupTest() {
    }

    ~D4GroupTest() {
    }

    void setUp() {
        root = new D4Group("");
        named = new D4Group("test");
        xml = new XMLWriter;
    }

    void tearDown() {
        delete xml;
        delete root;
        delete named;
    }

    void load_group_with_scalars(D4Group *g) {
        g->add_var_nocopy(new Byte("b"));
        g->add_var_nocopy(new Int64("i64"));
    }

    void load_group_with_stuff(D4Group *g) {
        g->dims()->add_dim_nocopy(new D4Dimension("lat", 1024));
        g->dims()->add_dim_nocopy(new D4Dimension("lon", 1024));
        g->dims()->add_dim_nocopy(new D4Dimension("time"));

        D4EnumDef *color_values = new D4EnumDef("colors", dods_byte_c);
        color_values->add_value("red", 1);
        color_values->add_value("green", 2);
        color_values->add_value("blue", 3);
        g->enum_defs()->add_enum_nocopy(color_values);

        g->get_attr_table().append_attr("test", "Int16", "1");
    }

    // An empty D4Group object prints nothing; the XMLWriter class adds
    // a xml doc preface.
    void test_print_empty() {
        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_empty.xml");
        DBG(cerr << "test_print_empty: doc: " << doc << endl);
        DBG(cerr << "test_print_empty: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_named_empty() {
        named->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_named_empty.xml");
        DBG(cerr << "test_print_named_empty: doc: " << doc << endl);
        DBG(cerr << "test_print_named_empty: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_with_vars() {
        load_group_with_scalars(root);

        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_with_scalars.xml");
        DBG(cerr << "test_print_with_vars: doc: " << doc << endl);
        DBG(cerr << "test_print_with_vars: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_named_with_vars() {
        load_group_with_scalars(named);

        named->print_dap4(*xml);

        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_named_with_scalars.xml");
        DBG(cerr << "test_print_named_with_vars: doc: " << doc << endl);
        DBG(cerr << "test_print_named_with_vars: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_with_vars_and_stuff() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_with_scalars_and_stuff.xml");
        DBG(cerr << "test_print_with_vars_and_stuff: doc: " << doc << endl);
        DBG(cerr << "test_print_with_vars_and_stuff: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_named_with_vars_and_stuff() {
        load_group_with_scalars(named);
        load_group_with_stuff(named);

        named->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_named_with_scalars_and_stuff.xml");
        DBG(cerr << "test_print_named_with_vars_and_stuff: doc: " << doc << endl);
        DBG(cerr << "test_print_named_with_vars_and_stuff: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_everything() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        D4Group *child = new D4Group("child");
        load_group_with_scalars(child);
        load_group_with_stuff(child);
        root->add_group(child);

        // Used add_group() and not add_group_nocopy()
        delete child;

        root->print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_everything.xml");
        DBG(cerr << "test_print_with_vars_and_stuff: doc: " << doc << endl);
        DBG(cerr << "test_print_with_vars_and_stuff: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_copy_ctor() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        D4Group *child = new D4Group("child");
        load_group_with_scalars(child);
        load_group_with_stuff(child);
        root->add_group_nocopy(child); // add it using ...nocopy() this time

        D4Group lhs(*root);

        lhs.print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_everything.xml");
        DBG(cerr << "test_print_copy_ctor: doc: " << doc << endl);
        DBG(cerr << "test_print_copy_ctor: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    void test_print_assignment() {
        load_group_with_scalars(root);
        load_group_with_stuff(root);

        D4Group *child = new D4Group("child");
        load_group_with_scalars(child);
        load_group_with_stuff(child);
        root->add_group_nocopy(child);

        D4Group lhs = *root;

        lhs.print_dap4(*xml);
        string doc = xml->get_doc();
        string baseline = readTestBaseline(string(TEST_SRC_DIR) + "/D4-xml/D4Group_everything.xml");
        DBG(cerr << "test_print_assignment: doc: " << doc << endl);
        DBG(cerr << "test_print_assignment: baseline: " << baseline << endl);
        CPPUNIT_ASSERT(doc == baseline);
    }

    CPPUNIT_TEST_SUITE( D4GroupTest );

        CPPUNIT_TEST(test_print_empty);

        CPPUNIT_TEST(test_print_named_empty);
        CPPUNIT_TEST(test_print_with_vars);
        CPPUNIT_TEST(test_print_named_with_vars);

        CPPUNIT_TEST(test_print_with_vars_and_stuff);

        CPPUNIT_TEST(test_print_named_with_vars_and_stuff);
        CPPUNIT_TEST(test_print_everything);

        CPPUNIT_TEST(test_print_copy_ctor);
        CPPUNIT_TEST(test_print_assignment);

    CPPUNIT_TEST_SUITE_END();
};

CPPUNIT_TEST_SUITE_REGISTRATION(D4GroupTest);

int main(int, char**) {
    CppUnit::TextTestRunner runner;
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());

    bool wasSuccessful = runner.run("", false);

    return wasSuccessful ? 0 : 1;
}

<|endoftext|>


<commit_before>#include "OutputGeometry.h"
#include "OutputGeometryPart.h"
#include "OutputObject.h"
#include "util.h"
#include "AssetNode.h"

OutputGeometry::OutputGeometry(HAPI_NodeId nodeId) :
    myNodeId(nodeId),
    myLastCookCount(0)
{
    update();
}

OutputGeometry::~OutputGeometry()
{
    for(int i = myParts.size(); i-- > 0;)
    {
        delete myParts.back();
        myParts.pop_back();
    }
}

void
OutputGeometry::update()
{
    HAPI_Result hapiResult;

    hapiResult = HAPI_GetNodeInfo(
            Util::theHAPISession.get(),
            myNodeId, &myNodeInfo
            );
    CHECK_HAPI(hapiResult);

    hapiResult = HAPI_GetGeoInfo(
            Util::theHAPISession.get(),
            myNodeId,
            &myGeoInfo);
    if(HAPI_FAIL(hapiResult))
    {
        // Make sre myGeoInfo is properly initialized.
        HAPI_GeoInfo_Init(&myGeoInfo);

        // Even when HAPI_GetGeoInfo() failed, there's always at least one
        // part. So we want the below code to initialize myParts.
    }

    if(myGeoInfo.type == HAPI_GEOTYPE_DEFAULT
            || myGeoInfo.type == HAPI_GEOTYPE_INTERMEDIATE
            || myGeoInfo.type == HAPI_GEOTYPE_CURVE)
    {
        // Create any new OutputGeometryPart
        myParts.reserve(myGeoInfo.partCount);
        for(int i = myParts.size(); i < myGeoInfo.partCount; i++)
        {
            OutputGeometryPart* outputGeometryPart = new OutputGeometryPart(
                    myNodeId,
                    i
                    );
            myParts.push_back(outputGeometryPart);
        }

        // Destroy the extra OutputGeometryPart
        for(int i = myParts.size(); i-- > myGeoInfo.partCount;)
        {
            delete myParts.back();
            myParts.pop_back();
        }
    }
}

MStatus
OutputGeometry::compute(
        const MTime &time,
        const MPlug &geoPlug,
        MDataBlock &data,
        MDataHandle &geoHandle,
        AssetNodeOptions::AccessorDataBlock &options,
        bool &needToSyncOutputs
        )
{
    MStatus stat;

    data.setClean(geoPlug);

    update();

    MDataHandle geoNameHandle = geoHandle.child(AssetNode::outputGeoName);
    MString geoName;
    if(myGeoInfo.nameSH != 0)
    {
        geoName = Util::HAPIString(myGeoInfo.nameSH);
    }
    geoNameHandle.setString(geoName);

    MDataHandle isTemplatedHandle = geoHandle.child(AssetNode::outputGeoIsTemplated);
    isTemplatedHandle.setBool(myGeoInfo.isTemplated);

    MDataHandle isDisplayGeoHandle = geoHandle.child(AssetNode::outputGeoIsDisplayGeo);
    isDisplayGeoHandle.setBool(myGeoInfo.isDisplayGeo);

    MPlug partsPlug = geoPlug.child(AssetNode::outputParts);
    MDataHandle partsHandle = geoHandle.child(AssetNode::outputParts);
    MArrayDataHandle partsArrayHandle(partsHandle);

    bool partCountChanged = partsArrayHandle.elementCount() != (unsigned int)myGeoInfo.partCount;
    if(partCountChanged)
    {
        Util::resizeArrayDataHandle(partsArrayHandle, myGeoInfo.partCount);
        needToSyncOutputs = true;
    }

    bool forceCompute = false;
    for(int i = 0; i < myGeoInfo.partCount; i++)
    {
        forceCompute |= myParts[i]->needCompute(options);
    }

    if(myGeoInfo.type == HAPI_GEOTYPE_DEFAULT ||
            myGeoInfo.type == HAPI_GEOTYPE_INTERMEDIATE ||
            myGeoInfo.type == HAPI_GEOTYPE_CURVE)
    {
        if(myNodeInfo.totalCookCount > myLastCookCount
                || partCountChanged || forceCompute)
        {
            // Compute the OutputGeometryPart
            for(int i = 0; i < myGeoInfo.partCount; i++)
            {
                MPlug partPlug = partsPlug.elementByLogicalIndex(i);

                CHECK_MSTATUS(partsArrayHandle.jumpToArrayElement(i));
                MDataHandle partHandle = partsArrayHandle.outputValue();

                stat = myParts[i]->compute(
                        time,
                        partPlug,
                        data,
                        partHandle,
                        options,
                        needToSyncOutputs
                        );
                CHECK_MSTATUS_AND_RETURN(stat, MS::kFailure);
            }
        }
        else
        {
            // even if nothing changed, clean the plugs
            for(int i = 0; i < myGeoInfo.partCount; i++)
            {
                MPlug partPlug = partsPlug.elementByLogicalIndex(i);

                MPlugArray childPlugs;
                Util::getChildPlugs(childPlugs, partPlug);
                for(unsigned int j = 0; j < childPlugs.length(); j++)
                {
                    data.setClean(childPlugs[j]);
                }
            }
        }
    }

    myLastCookCount = myNodeInfo.totalCookCount;

    return MS::kSuccess;
}
<commit_msg>fix for plugin crash when asset has an output null that HAPI has, for whatever reason, identified as an input.<commit_after>#include "OutputGeometry.h"
#include "OutputGeometryPart.h"
#include "OutputObject.h"
#include "util.h"
#include "AssetNode.h"

OutputGeometry::OutputGeometry(HAPI_NodeId nodeId) :
    myNodeId(nodeId),
    myLastCookCount(0)
{
    update();
}

OutputGeometry::~OutputGeometry()
{
    for(int i = myParts.size(); i-- > 0;)
    {
        delete myParts.back();
        myParts.pop_back();
    }
}

void
OutputGeometry::update()
{
    HAPI_Result hapiResult;

    hapiResult = HAPI_GetNodeInfo(
            Util::theHAPISession.get(),
            myNodeId, &myNodeInfo
            );
    CHECK_HAPI(hapiResult);

    hapiResult = HAPI_GetGeoInfo(
            Util::theHAPISession.get(),
            myNodeId,
            &myGeoInfo);
    if(HAPI_FAIL(hapiResult))
    {
        // Make sre myGeoInfo is properly initialized.
        HAPI_GeoInfo_Init(&myGeoInfo);

        // Even when HAPI_GetGeoInfo() failed, there's always at least one
        // part. So we want the below code to initialize myParts.
    }

    if(myGeoInfo.type == HAPI_GEOTYPE_DEFAULT
            || myGeoInfo.type == HAPI_GEOTYPE_INTERMEDIATE
            || myGeoInfo.type == HAPI_GEOTYPE_INPUT
            || myGeoInfo.type == HAPI_GEOTYPE_CURVE)
    {
        // Create any new OutputGeometryPart
        myParts.reserve(myGeoInfo.partCount);
        for(int i = myParts.size(); i < myGeoInfo.partCount; i++)
        {
            OutputGeometryPart* outputGeometryPart = new OutputGeometryPart(
                    myNodeId,
                    i
                    );
            myParts.push_back(outputGeometryPart);
        }

        // Destroy the extra OutputGeometryPart
        for(int i = myParts.size(); i-- > myGeoInfo.partCount;)
        {
            delete myParts.back();
            myParts.pop_back();
        }
    }
}

MStatus
OutputGeometry::compute(
        const MTime &time,
        const MPlug &geoPlug,
        MDataBlock &data,
        MDataHandle &geoHandle,
        AssetNodeOptions::AccessorDataBlock &options,
        bool &needToSyncOutputs
        )
{
    MStatus stat;

    data.setClean(geoPlug);

    update();

    MDataHandle geoNameHandle = geoHandle.child(AssetNode::outputGeoName);
    MString geoName;
    if(myGeoInfo.nameSH != 0)
    {
        geoName = Util::HAPIString(myGeoInfo.nameSH);
    }
    geoNameHandle.setString(geoName);

    MDataHandle isTemplatedHandle = geoHandle.child(AssetNode::outputGeoIsTemplated);
    isTemplatedHandle.setBool(myGeoInfo.isTemplated);

    MDataHandle isDisplayGeoHandle = geoHandle.child(AssetNode::outputGeoIsDisplayGeo);
    isDisplayGeoHandle.setBool(myGeoInfo.isDisplayGeo);

    MPlug partsPlug = geoPlug.child(AssetNode::outputParts);
    MDataHandle partsHandle = geoHandle.child(AssetNode::outputParts);
    MArrayDataHandle partsArrayHandle(partsHandle);

    bool partCountChanged = partsArrayHandle.elementCount() != (unsigned int)myGeoInfo.partCount;
    if(partCountChanged)
    {
        Util::resizeArrayDataHandle(partsArrayHandle, myGeoInfo.partCount);
        needToSyncOutputs = true;
    }

    bool forceCompute = false;
    for(int i = 0; i < myGeoInfo.partCount; i++)
    {
        forceCompute |= myParts[i]->needCompute(options);
    }

    // if we got here it's an output, even if HAPI thinks it's an input too
    if(myGeoInfo.type == HAPI_GEOTYPE_DEFAULT ||
            myGeoInfo.type == HAPI_GEOTYPE_INTERMEDIATE ||
            myGeoInfo.type == HAPI_GEOTYPE_INPUT ||
            myGeoInfo.type == HAPI_GEOTYPE_CURVE)
    {
        if(myNodeInfo.totalCookCount > myLastCookCount
                || partCountChanged || forceCompute)
        {
            // Compute the OutputGeometryPart
            for(int i = 0; i < myGeoInfo.partCount; i++)
            {
                MPlug partPlug = partsPlug.elementByLogicalIndex(i);

                CHECK_MSTATUS(partsArrayHandle.jumpToArrayElement(i));
                MDataHandle partHandle = partsArrayHandle.outputValue();

                stat = myParts[i]->compute(
                        time,
                        partPlug,
                        data,
                        partHandle,
                        options,
                        needToSyncOutputs
                        );
                CHECK_MSTATUS_AND_RETURN(stat, MS::kFailure);
            }
        }
        else
        {
            // even if nothing changed, clean the plugs
            for(int i = 0; i < myGeoInfo.partCount; i++)
            {
                MPlug partPlug = partsPlug.elementByLogicalIndex(i);

                MPlugArray childPlugs;
                Util::getChildPlugs(childPlugs, partPlug);
                for(unsigned int j = 0; j < childPlugs.length(); j++)
                {
                    data.setClean(childPlugs[j]);
                }
            }
        }
    }

    myLastCookCount = myNodeInfo.totalCookCount;

    return MS::kSuccess;
}
<|endoftext|>


<commit_before>#include "gtest.h"
#include "proposer.h"

class ProposerTest : public testing::Test {
protected:

	int id;
	int instances;
	struct proposer* p;

	virtual void SetUp() {
		id = 2;
		instances = 100;
		p = proposer_new(id, instances);
	}

	virtual void TearDown() { }
};

TEST_F(ProposerTest, Prepare) {
	int count = 10;
	prepare_req pr;
	for (int i = 0; i < count; ++i) {
		pr = proposer_prepare(p);
		ASSERT_EQ(pr.iid, i+1);
		ASSERT_EQ(pr.ballot, id + MAX_N_OF_PROPOSERS);
	}
	ASSERT_EQ(count, proposer_prepared_count(p));
}

TEST_F(ProposerTest, PrepareAndAccept) {
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	accept_ack aa;

	pr = proposer_prepare(p);

	// aid, iid, bal, val_bal, val_size
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);
	pa = (prepare_ack) {2, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);

	// we have no value to propose!
	ASSERT_EQ(proposer_accept(p), (void*)NULL);

	proposer_propose(p, (char*)"value", 6);
	ar = proposer_accept(p);
	ASSERT_NE(ar, (accept_req*)NULL);
	ASSERT_EQ(ar->iid, pr.iid);
	ASSERT_EQ(ar->ballot, pr.ballot);
	ASSERT_EQ(ar->value_size, 6);
	ASSERT_STREQ(ar->value, "value");

	// aid, iid, bal, val_bal, final, size
	prepare_req* req;
	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
}

TEST_F(ProposerTest, PreparePreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	// preempt! proposer receives a different ballot...
	pa = (prepare_ack) {1, pr.iid, pr.ballot+1, 0, 0};
	pr_preempt = proposer_receive_prepare_ack(p, &pa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, pr.ballot);

	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(ar->iid, pr_preempt->iid);
	ASSERT_EQ(ar->ballot, pr_preempt->ballot);
	ASSERT_EQ(ar->value_size, value_size);
	ASSERT_STREQ(ar->value, value);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, AcceptPreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	accept_ack aa;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	pa = (prepare_ack) {0, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);

	// preempt! proposer receives accept nack
	aa = (accept_ack) {0, ar->iid, ar->ballot+1, 0, 0, 0};
	pr_preempt = proposer_receive_accept_ack(p, &aa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, ar->ballot);
	free(ar);

	// finally acquire the instance
	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	// accept again
	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(pr_preempt->iid, ar->iid);
	ASSERT_EQ(pr_preempt->ballot, ar->ballot);
	ASSERT_EQ(value_size, ar->value_size);
	ASSERT_STREQ(value, ar->value);

	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, PreparedCount) {
	int count = 10;
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	char value[] = "a value";
	int value_size = strlen(value) + 1;

	for (size_t i = 0; i < count; ++i) {
		pr = proposer_prepare(p);
		proposer_propose(p, value, value_size);
		ASSERT_EQ(i + 1, proposer_prepared_count(p));
	}

	for (size_t i = 0; i < count; ++i)
		proposer_accept(p);
	ASSERT_EQ(count, proposer_prepared_count(p));

	for (size_t i = 0; i < count; ++i) {
		pa = (prepare_ack) {0, i+1, pr.ballot, 0, 0};
		proposer_receive_prepare_ack(p, &pa);
		pa = (prepare_ack) {1, i+1, pr.ballot, 0, 0};
		proposer_receive_prepare_ack(p, &pa);
		ar = proposer_accept(p);
		free(ar);
		ASSERT_EQ(count-(i+1), proposer_prepared_count(p));
	}
}
<commit_msg>Improves AcceptPreemptedTest.<commit_after>#include "gtest.h"
#include "proposer.h"

class ProposerTest : public testing::Test {
protected:

	int id;
	int instances;
	struct proposer* p;

	virtual void SetUp() {
		id = 2;
		instances = 100;
		p = proposer_new(id, instances);
	}

	virtual void TearDown() { }
};

TEST_F(ProposerTest, Prepare) {
	int count = 10;
	prepare_req pr;
	for (int i = 0; i < count; ++i) {
		pr = proposer_prepare(p);
		ASSERT_EQ(pr.iid, i+1);
		ASSERT_EQ(pr.ballot, id + MAX_N_OF_PROPOSERS);
	}
	ASSERT_EQ(count, proposer_prepared_count(p));
}

TEST_F(ProposerTest, PrepareAndAccept) {
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	accept_ack aa;

	pr = proposer_prepare(p);

	// aid, iid, bal, val_bal, val_size
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);
	pa = (prepare_ack) {2, pr.iid, pr.ballot, 0, 0};
	proposer_receive_prepare_ack(p, &pa);

	// we have no value to propose!
	ASSERT_EQ(proposer_accept(p), (void*)NULL);

	proposer_propose(p, (char*)"value", 6);
	ar = proposer_accept(p);
	ASSERT_NE(ar, (accept_req*)NULL);
	ASSERT_EQ(ar->iid, pr.iid);
	ASSERT_EQ(ar->ballot, pr.ballot);
	ASSERT_EQ(ar->value_size, 6);
	ASSERT_STREQ(ar->value, "value");

	// aid, iid, bal, val_bal, final, size
	prepare_req* req;
	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
}

TEST_F(ProposerTest, PreparePreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	// preempt! proposer receives a different ballot...
	pa = (prepare_ack) {1, pr.iid, pr.ballot+1, 0, 0};
	pr_preempt = proposer_receive_prepare_ack(p, &pa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, pr.ballot);

	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(ar->iid, pr_preempt->iid);
	ASSERT_EQ(ar->ballot, pr_preempt->ballot);
	ASSERT_EQ(ar->value_size, value_size);
	ASSERT_STREQ(ar->value, value);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, AcceptPreempted) {
	prepare_req pr;
	prepare_ack pa;
	prepare_req* pr_preempt;
	accept_req* ar;
	accept_ack aa;
	char value[] = "some value";
	int value_size = strlen(value) + 1;

	pr = proposer_prepare(p);
	proposer_propose(p, value, value_size);

	pa = (prepare_ack) {0, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr.iid, pr.ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);

	// preempt! proposer receives accept nack
	aa = (accept_ack) {0, ar->iid, ar->ballot+1, 0, 0, 0};
	pr_preempt = proposer_receive_accept_ack(p, &aa);
	ASSERT_NE((void*)NULL, pr_preempt);
	ASSERT_EQ(pr_preempt->iid, pr.iid);
	ASSERT_GT(pr_preempt->ballot, ar->ballot);
	free(ar);

	// check that proposer pushed the instance back
	// to the prepare phase
	ASSERT_EQ(proposer_prepared_count(p), 1);

	// finally acquire the instance
	pa = (prepare_ack) {0, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);
	pa = (prepare_ack) {1, pr_preempt->iid, pr_preempt->ballot, 0, 0};
	ASSERT_EQ(proposer_receive_prepare_ack(p, &pa), (void*)NULL);

	// accept again
	ar = proposer_accept(p);
	ASSERT_NE(ar, (void*)NULL);
	ASSERT_EQ(pr_preempt->iid, ar->iid);
	ASSERT_EQ(pr_preempt->ballot, ar->ballot);
	ASSERT_EQ(value_size, ar->value_size);
	ASSERT_STREQ(value, ar->value);

	aa = (accept_ack) {0, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);
	aa = (accept_ack) {1, ar->iid, ar->ballot, ar->ballot, 0, value_size};
	ASSERT_EQ(proposer_receive_accept_ack(p, &aa), (void*)NULL);

	free(ar);
	free(pr_preempt);
}

TEST_F(ProposerTest, PreparedCount) {
	int count = 10;
	prepare_req pr;
	prepare_ack pa;
	accept_req* ar;
	char value[] = "a value";
	int value_size = strlen(value) + 1;

	for (size_t i = 0; i < count; ++i) {
		pr = proposer_prepare(p);
		proposer_propose(p, value, value_size);
		ASSERT_EQ(i + 1, proposer_prepared_count(p));
	}

	for (size_t i = 0; i < count; ++i)
		proposer_accept(p);
	ASSERT_EQ(count, proposer_prepared_count(p));

	for (size_t i = 0; i < count; ++i) {
		pa = (prepare_ack) {0, i+1, pr.ballot, 0, 0};
		proposer_receive_prepare_ack(p, &pa);
		pa = (prepare_ack) {1, i+1, pr.ballot, 0, 0};
		proposer_receive_prepare_ack(p, &pa);
		ar = proposer_accept(p);
		free(ar);
		ASSERT_EQ(count-(i+1), proposer_prepared_count(p));
	}
}
<|endoftext|>


<commit_before><commit_msg>Fixes bug in views on gtk where we wouldn't necessarily paint correctly on an expose. This happened if between the time we told Gtk we needed to paint and the time we got the expose event more paints were scheduled. In this case, because we were double buffered, GTK would clip to the original region we scheduled the paint for. The fix is to turn off double buffering as we're double buffering ourself.<commit_after><|endoftext|>


<commit_before>#include "node.hh"

namespace doanimate {
	namespace nodes {
		void default_node::update() {
			outputs = implementation(inputs);
		}

		std::vector<types::value>& default_node::get_inputs() {
			return inputs;
		}

		const std::vector<types::value>& default_node::get_outputs() {
			return outputs;
		}

		const std::vector<types::type_info>& default_node::get_input_type_infos() {
			return input_type_infos;
		}

		const std::vector<types::type_info>& default_node::get_output_type_infos() {
			return output_type_infos;
		}
	}
}
<commit_msg>Changed type names to lowercase in node.cc<commit_after>#include "node.hh"

namespace doanimate {
	namespace nodes {
		void DefaultNode::update() {
			outputs = implementation(inputs);
		}

		std::vector<types::Value>& DefaultNode::get_inputs() {
			return inputs;
		}

		const std::vector<types::Value>& DefaultNode::get_outputs() {
			return outputs;
		}

		const std::vector<types::TypeInfo>& DefaultNode::get_input_type_infos() {
			return input_type_infos;
		}

		const std::vector<types::TypeInfo>& DefaultNode::get_output_type_infos() {
			return output_type_infos;
		}
	}
}
<|endoftext|>


<commit_before>// SimClientTest.cpp : Defines the entry point for the console application.
//
#include <string>
#include <atlbase.h>
#include <iostream>

#include "SimIntefaceHelper.h"
#include "CwSidetoneNotifyImpl.h"

namespace {
    void DoWithCOM();
    int DemoSidetone(IKnowDispatchIsManagerPtr pMgr);
    void DemoCwQso(IKnowDispatchIsManagerPtr pMgr);
    void DemoRtty(IKnowDispatchIsManagerPtr pMgr);
}

int main(int argc, char* argv[])
{
    ::CoInitialize(0);
    DoWithCOM();    // COM objects must be released BEFORE CoUninitialize
    ::CoUninitialize();
	return 0;
}

namespace
{
    void DoWithCOM()
    {
        try
        {

            // For the interfaces named:
            //      IKnowDispatchIsManager
            //      IKnowDispatchIsCwSimulator
            //      IKnowDispatchIsRadioSimulator
            // If we used an admin install of the interfaces, we could make
            // Windows "marshall" the above interfaces..
            //
            // But they are just IDispatch which has a built-in marshaller. Sowe just use
            // some goop in SimInterfaceHelper.h to convince the Microsoft C++ compiler to
            // attach its IDispatch helpers to an unaddorned IDispatch interface.

            // The simulator manager registers itself in the ROT when the user runs it.
            IKnowDispatchIsManagerPtr        pMgr;
            pMgr.GetActiveObject(__uuidof(ContestSuperSimDispLib::SuperSimManager));

            char c; // place to read for cin to block for user input
            if (!pMgr)
            {
                std::cout << "SuperSimManager not active" << std::endl;
                std::cin.read(&c, 1);
                return;
            }

            // The manager object provides access to the virtual radio objects.
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(
                                                            0   /* zero-based index of radio number */
                                                            );

            // The simulator puts its virtual radios on frequencies of its own choosing. See what that is:
            std::cout << "Got radio of frequency: " << pRadio->CenterFrequency << " KHz. ENTER to continue" << std::endl;
            std::cin.read(&c, 1);

            int yesno = DemoSidetone(pMgr);
            if (yesno == IDNO)
            {
                pMgr->GetCwSidetoneGenerator(0); // make simulator let go of our notifier
                return;
            }

            DemoCwQso(pMgr);

            yesno = ::MessageBox(0, "Try RTTY?", "SimClientTest", MB_YESNO);

            if (yesno == IDYES)
            {
                DemoRtty(pMgr);
            }

        }
        catch (const std::exception &e)
        {
            std::cerr << "Caught exception " << e.what() << std::endl;
        }
        catch (const _com_error &e)
        {
            std::cerr << "Caught COM exception " << e.ErrorMessage() << std::endl;
        }
    }

    int DemoSidetone(IKnowDispatchIsManagerPtr pMgr)
    {
            // Nothing here but sidetone generation
            // Client of simulator can call its winkey emulation or call on
            // its ICwSimulator, but its redundant to do both.
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(0);
            CComPtr<MyNotifier>pNotify = new MyNotifier();

            IKnowDispatchIsCwSimulatorPtr pCwSidetone =
                pMgr->GetCwSidetoneGenerator(pNotify);

            if (!pCwSidetone)
            {
                std::cout << "GetCwSidetoneGenerate returned empty!" << std::endl;
                return IDNO;
            }

            pCwSidetone->PutWPM(25);
            pCwSidetone->QueueToTransmitText("test de w5xd");
            pCwSidetone->QueueWpmChange(35);
            pCwSidetone->QueueToTransmitText("test test w5xd");
            int yesno = ::MessageBox(0, "Yes to continue, No to Exit", "SimClientTest", MB_YESNO);
            pCwSidetone->AbortTransmission(); // if you OK fast enough, the transmission in progress will be aborted
            return yesno;
    }

    void DemoCwQso(IKnowDispatchIsManagerPtr pMgr)
    {
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(0);

             // see if we can get the simulator to answer us
            _bstr_t msg("CQ TEST DE W5XD");

            // Demonstrate the timing sequence.
            CComPtr<MyNotifier>pNotify = new MyNotifier(
                // this callback happens when the CQ finishes..
                // Will ALSO get call backs for WinKey-initiated message finished...
                // should not support both.
                    [pRadio, msg]() {
                    pRadio->MessageCompletedNow("CW", msg); // tell the simulator our CQ is over
                });

            IKnowDispatchIsCwSimulatorPtr pCwSidetone = pMgr->GetCwSidetoneGenerator(pNotify);
            pCwSidetone->PutWPM(25); // Lets do a typical contest CQ speed

            for (;;)
            {
                pRadio->MessageStartedNow();
                pCwSidetone->QueueToTransmitText(msg);
                int yesno = ::MessageBox(0, "CQ again? No to Exit", "SimClientTest", MB_YESNO);
                if (yesno == IDNO)
                    break;
            }
   }

    void DemoRtty(IKnowDispatchIsManagerPtr pMgr)
    {
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(0);

            // tune the virtual radio to RTTY
            // This demo would work on the simulator's default frequency, but
            // this one is a more conventional RTTY frequency.
            pRadio->SetListenFrequency(7080, "RY");

             // see if we can get the simulator to answer us
            _bstr_t msg("CQ TEST DE W5XD");

            for (;;)
            {
                pRadio->MessageStartedNow();
                bool stop = ::MessageBox(0, "Simulator thinks are sending RTTY now.\r\n OK to end the CQ (or cancel)", "SimClientTest", MB_YESNOCANCEL) != IDYES;
                if (stop)
                    break;
                pRadio->MessageCompletedNow("RY", msg);  // we call CQ in RTTY mode...the simulator may answer
                stop = ::MessageBox(0, "Again?", "SimClientTest", MB_YESNO) != IDYES;

            }

    }

}<commit_msg>more commentary<commit_after>// SimClientTest.cpp : Defines the entry point for the console application.
//
#include <string>
#include <atlbase.h>
#include <iostream>

#include "SimIntefaceHelper.h"
#include "CwSidetoneNotifyImpl.h"

namespace {
    void DoWithCOM();
    int DemoSidetone(IKnowDispatchIsManagerPtr pMgr);
    void DemoCwQso(IKnowDispatchIsManagerPtr pMgr);
    void DemoRtty(IKnowDispatchIsManagerPtr pMgr);
}

int main(int argc, char* argv[])
{
    ::CoInitialize(0);
    DoWithCOM();    // COM objects must be released BEFORE CoUninitialize
    ::CoUninitialize();
	return 0;
}

namespace
{
    void DoWithCOM()
    {
        try
        {

            // For the interfaces named:
            //      IKnowDispatchIsManager
            //      IKnowDispatchIsCwSimulator
            //      IKnowDispatchIsRadioSimulator
            // If we used an admin install of the interfaces, we could make
            // Windows "marshall" the above interfaces..
            //
            // But they are just IDispatch which has a built-in marshaller. Sowe just use
            // some goop in SimInterfaceHelper.h to convince the Microsoft C++ compiler to
            // attach its IDispatch helpers to an unaddorned IDispatch interface.

            // The simulator manager registers itself in the ROT when the user runs it.
            IKnowDispatchIsManagerPtr        pMgr;
            pMgr.GetActiveObject(__uuidof(ContestSuperSimDispLib::SuperSimManager));

            char c; // place to read for cin to block for user input
            if (!pMgr)
            {
                std::cout << "SuperSimManager not active" << std::endl;
                std::cin.read(&c, 1);
                return;
            }

            // The manager object provides access to the virtual radio objects.
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(
                                                            0   /* zero-based index of radio number */
                                                            );

            // The simulator puts its virtual radios on frequencies of its own choosing. See what that is:
            std::cout << "Got radio of frequency: " << pRadio->CenterFrequency << " KHz. ENTER to continue" << std::endl;
            std::cin.read(&c, 1);

            int yesno = DemoSidetone(pMgr);
            if (yesno == IDNO)
            {
                pMgr->GetCwSidetoneGenerator(0); // make simulator let go of our notifier
                return;
            }

            DemoCwQso(pMgr);

            // Why does this demo switch back and forth between using cout/cin and
            // MessageBox?
            // The distinction is important because we called CoInitialize(0); (way
            // back in the first line in main).
            // We won't get any COM callbacks while stuck reading cin. But we
            // will if we're in MessageBox.
            // That difference is important to the simulator for only one scenario:
            // when you pass a non-null argument to GetCwSidetoneGenerator()
            // The object you pass will only get called through a Windows message
            yesno = ::MessageBox(0, "Try RTTY?", "SimClientTest", MB_YESNO);

            if (yesno == IDYES)
                DemoRtty(pMgr);

        }
        catch (const std::exception &e)
        {
            std::cerr << "Caught exception " << e.what() << std::endl;
        }
        catch (const _com_error &e)
        {
            std::cerr << "Caught COM exception " << e.ErrorMessage() << std::endl;
        }
    }

    int DemoSidetone(IKnowDispatchIsManagerPtr pMgr)
    {
            // Nothing here but sidetone generation
            // Client of simulator can call its winkey emulation or call on
            // its ICwSimulator, but its redundant to do both.
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(0);
            CComPtr<MyNotifier>pNotify = new MyNotifier();

            IKnowDispatchIsCwSimulatorPtr pCwSidetone =
                pMgr->GetCwSidetoneGenerator(pNotify);

            if (!pCwSidetone)
            {
                std::cout << "GetCwSidetoneGenerate returned empty!" << std::endl;
                return IDNO;
            }

            pCwSidetone->PutWPM(25);
            pCwSidetone->QueueToTransmitText("test de w5xd");
            pCwSidetone->QueueWpmChange(35);
            pCwSidetone->QueueToTransmitText("test test w5xd");
            int yesno = ::MessageBox(0, "Yes to continue, No to Exit", "SimClientTest", MB_YESNO);
            pCwSidetone->AbortTransmission(); // if you OK fast enough, the transmission in progress will be aborted
            return yesno;
    }

    void DemoCwQso(IKnowDispatchIsManagerPtr pMgr)
    {
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(0);

             // see if we can get the simulator to answer us
            _bstr_t msg("CQ TEST DE W5XD");

            // Demonstrate the timing sequence.
            CComPtr<MyNotifier>pNotify = new MyNotifier(
                // this callback happens when the CQ finishes..
                // Will ALSO get call backs for WinKey-initiated message finished...
                // should not support both.
                    [pRadio, msg]() {
                    pRadio->MessageCompletedNow("CW", msg); // tell the simulator our CQ is over
                });

            IKnowDispatchIsCwSimulatorPtr pCwSidetone = pMgr->GetCwSidetoneGenerator(pNotify);
            pCwSidetone->PutWPM(25); // Lets do a typical contest CQ speed

            for (;;)
            {
                pRadio->MessageStartedNow();
                pCwSidetone->QueueToTransmitText(msg);
                int yesno = ::MessageBox(0, "CQ again? No to Exit", "SimClientTest", MB_YESNO);
                if (yesno == IDNO)
                    break;
            }
   }

    void DemoRtty(IKnowDispatchIsManagerPtr pMgr)
    {
            IKnowDispatchIsRadioSimulatorPtr pRadio =  pMgr->GetSimulatorForRadio(0);

            // tune the virtual radio to RTTY
            // This demo would work on the simulator's default frequency, but
            // this one is a more conventional RTTY frequency.
            pRadio->SetListenFrequency(7080, "RY");

             // see if we can get the simulator to answer us
            _bstr_t msg("CQ TEST DE W5XD");

            for (;;)
            {
                pRadio->MessageStartedNow();
                bool stop = ::MessageBox(0, "Simulator thinks are sending RTTY now.\r\n OK to end the CQ (or cancel)", "SimClientTest", MB_YESNOCANCEL) != IDYES;
                if (stop)
                    break;
                pRadio->MessageCompletedNow("RY", msg);  // we call CQ in RTTY mode...the simulator may answer
                stop = ::MessageBox(0, "Again?", "SimClientTest", MB_YESNO) != IDYES;

            }

    }

}<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <iostream>
#include <sstream>
#include <vector>
#include <string>

#include <mapnik/version.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#pragma GCC diagnostic pop

#include "agg_rasterizer_scanline_aa.h"
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_renderer_base.h"
#include "agg_pixfmt_rgba.h"
#include "agg_scanline_u.h"

#include <libxml/parser.h> // for xmlInitParser(), xmlCleanupParser()

struct main_marker_visitor
{
    main_marker_visitor(std::string const& svg_name,
                        bool verbose,
                        bool auto_open)
        : svg_name_(svg_name),
          verbose_(verbose),
          auto_open_(auto_open) {}

    int operator() (mapnik::marker_svg const& marker)
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::rasterizer_scanline_aa<> ras_ptr;
        agg::scanline_u8 sl;

        double opacity = 1;
        int w = marker.width();
        int h = marker.height();
        if (verbose_)
        {
            std::clog << "found width of '" << w << "' and height of '" << h << "'\n";
        }
        // 10 pixel buffer to avoid edge clipping of 100% svg's
        mapnik::image_rgba8 im(w+0,h+0);
        agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        mapnik::box2d<double> const& bbox = marker.get_data()->bounding_box();
        mapnik::coord<double,2> c = bbox.center();
        // center the svg marker on '0,0'
        agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
        // render the marker at the center of the marker box
        mtx.translate(0.5 * im.width(), 0.5 * im.height());

        mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(marker.get_data()->source());
        mapnik::svg::svg_path_adapter svg_path(stl_storage);
        mapnik::svg::svg_renderer_agg<mapnik::svg::svg_path_adapter,
            agg::pod_bvector<mapnik::svg::path_attributes>,
            renderer_solid,
            agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path,
                                                       marker.get_data()->attributes());

        svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);

        std::string png_name(svg_name_);
        boost::algorithm::ireplace_last(png_name,".svg",".png");
        demultiply_alpha(im);
        mapnik::save_to_file<mapnik::image_rgba8>(im,png_name,"png");
        int status = 0;
        if (auto_open_)
        {
            std::ostringstream s;
#ifdef DARWIN
            s << "open " << png_name;
#else
            s << "xdg-open " << png_name;
#endif
            int ret = system(s.str().c_str());
            if (ret != 0)
                status = ret;
        }
        std::clog << "rendered to: " << png_name << "\n";
        return status;
    }

    // default
    template <typename T>
    int operator() (T const&)
    {
        std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n";
        return -1;
    }

  private:
    std::string const& svg_name_;
    bool verbose_;
    bool auto_open_;
};

int main (int argc,char** argv)
{
    namespace po = boost::program_options;

    bool verbose = false;
    bool auto_open = false;
    int status = 0;
    std::vector<std::string> svg_files;
    mapnik::logger::instance().set_severity(mapnik::logger::error);

    try
    {
        po::options_description desc("svg2png utility");
        desc.add_options()
            ("help,h", "produce usage message")
            ("version,V","print version string")
            ("verbose,v","verbose output")
            ("open","automatically open the file after rendering (os x only)")
            ("svg",po::value<std::vector<std::string> >(),"svg file to read")
            ;

        po::positional_options_description p;
        p.add("svg",-1);
        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        po::notify(vm);

        if (vm.count("version"))
        {
            std::clog <<"version " << MAPNIK_VERSION_STRING << std::endl;
            return 1;
        }

        if (vm.count("help"))
        {
            std::clog << desc << std::endl;
            return 1;
        }

        if (vm.count("verbose"))
        {
            verbose = true;
        }

        if (vm.count("open"))
        {
            auto_open = true;
        }

        if (vm.count("svg"))
        {
            svg_files=vm["svg"].as< std::vector<std::string> >();
        }
        else
        {
            std::clog << "please provide an svg file!" << std::endl;
            return -1;
        }

        std::vector<std::string>::const_iterator itr = svg_files.begin();
        if (itr == svg_files.end())
        {
            std::clog << "no svg files to render" << std::endl;
            return 0;
        }

        xmlInitParser();

        while (itr != svg_files.end())
        {
            std::string svg_name (*itr++);
            if (verbose)
            {
                std::clog << "found: " << svg_name << "\n";
            }

            std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
            main_marker_visitor visitor(svg_name, verbose, auto_open);
            status = mapnik::util::apply_visitor(visitor, *marker);
        }
    }
    catch (...)
    {
        std::clog << "Exception of unknown type!" << std::endl;
        xmlCleanupParser();
        return -1;
    }

    // only call this once, on exit
    // to make sure valgrind output is clean
    // http://xmlsoft.org/xmlmem.html
    xmlCleanupParser();
    return status;
}
<commit_msg>catch std::exception to get better stderr<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <iostream>
#include <sstream>
#include <vector>
#include <string>

#include <mapnik/version.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#pragma GCC diagnostic pop

#include "agg_rasterizer_scanline_aa.h"
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_renderer_base.h"
#include "agg_pixfmt_rgba.h"
#include "agg_scanline_u.h"

#include <libxml/parser.h> // for xmlInitParser(), xmlCleanupParser()

struct main_marker_visitor
{
    main_marker_visitor(std::string const& svg_name,
                        bool verbose,
                        bool auto_open)
        : svg_name_(svg_name),
          verbose_(verbose),
          auto_open_(auto_open) {}

    int operator() (mapnik::marker_svg const& marker)
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::rasterizer_scanline_aa<> ras_ptr;
        agg::scanline_u8 sl;

        double opacity = 1;
        int w = marker.width();
        int h = marker.height();
        if (verbose_)
        {
            std::clog << "found width of '" << w << "' and height of '" << h << "'\n";
        }
        // 10 pixel buffer to avoid edge clipping of 100% svg's
        mapnik::image_rgba8 im(w+0,h+0);
        agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        mapnik::box2d<double> const& bbox = marker.get_data()->bounding_box();
        mapnik::coord<double,2> c = bbox.center();
        // center the svg marker on '0,0'
        agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
        // render the marker at the center of the marker box
        mtx.translate(0.5 * im.width(), 0.5 * im.height());

        mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(marker.get_data()->source());
        mapnik::svg::svg_path_adapter svg_path(stl_storage);
        mapnik::svg::svg_renderer_agg<mapnik::svg::svg_path_adapter,
            agg::pod_bvector<mapnik::svg::path_attributes>,
            renderer_solid,
            agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path,
                                                       marker.get_data()->attributes());

        svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);

        std::string png_name(svg_name_);
        boost::algorithm::ireplace_last(png_name,".svg",".png");
        demultiply_alpha(im);
        mapnik::save_to_file<mapnik::image_rgba8>(im,png_name,"png");
        int status = 0;
        if (auto_open_)
        {
            std::ostringstream s;
#ifdef DARWIN
            s << "open " << png_name;
#else
            s << "xdg-open " << png_name;
#endif
            int ret = system(s.str().c_str());
            if (ret != 0)
                status = ret;
        }
        std::clog << "rendered to: " << png_name << "\n";
        return status;
    }

    // default
    template <typename T>
    int operator() (T const&)
    {
        std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n";
        return -1;
    }

  private:
    std::string const& svg_name_;
    bool verbose_;
    bool auto_open_;
};

int main (int argc,char** argv)
{
    namespace po = boost::program_options;

    bool verbose = false;
    bool auto_open = false;
    int status = 0;
    std::vector<std::string> svg_files;
    mapnik::logger::instance().set_severity(mapnik::logger::error);

    try
    {
        po::options_description desc("svg2png utility");
        desc.add_options()
            ("help,h", "produce usage message")
            ("version,V","print version string")
            ("verbose,v","verbose output")
            ("open","automatically open the file after rendering (os x only)")
            ("svg",po::value<std::vector<std::string> >(),"svg file to read")
            ;

        po::positional_options_description p;
        p.add("svg",-1);
        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        po::notify(vm);

        if (vm.count("version"))
        {
            std::clog <<"version " << MAPNIK_VERSION_STRING << std::endl;
            return 1;
        }

        if (vm.count("help"))
        {
            std::clog << desc << std::endl;
            return 1;
        }

        if (vm.count("verbose"))
        {
            verbose = true;
        }

        if (vm.count("open"))
        {
            auto_open = true;
        }

        if (vm.count("svg"))
        {
            svg_files=vm["svg"].as< std::vector<std::string> >();
        }
        else
        {
            std::clog << "please provide an svg file!" << std::endl;
            return -1;
        }

        std::vector<std::string>::const_iterator itr = svg_files.begin();
        if (itr == svg_files.end())
        {
            std::clog << "no svg files to render" << std::endl;
            return 0;
        }

        xmlInitParser();

        while (itr != svg_files.end())
        {
            std::string svg_name (*itr++);
            if (verbose)
            {
                std::clog << "found: " << svg_name << "\n";
            }

            std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
            main_marker_visitor visitor(svg_name, verbose, auto_open);
            status = mapnik::util::apply_visitor(visitor, *marker);
        }
    }
    catch (std::exception const& ex)
    {
        std::clog << "Exception caught:" << ex.what() << std::endl;
        xmlCleanupParser();
        return -1;
    }
    catch (...)
    {
        std::clog << "Exception of unknown type!" << std::endl;
        xmlCleanupParser();
        return -1;
    }

    // only call this once, on exit
    // to make sure valgrind output is clean
    // http://xmlsoft.org/xmlmem.html
    xmlCleanupParser();
    return status;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DateConversion.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 00:58:54 $
 *
 *  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 _CONNECTIVITY_DATECONVERSION_HXX_
#define _CONNECTIVITY_DATECONVERSION_HXX_

#ifndef _COM_SUN_STAR_UTIL_DATE_HPP_
#include <com/sun/star/util/Date.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_TIME_HPP_
#include <com/sun/star/util/Time.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
#include <com/sun/star/util/DateTime.hpp>
#endif

namespace connectivity
{
    class DateConversion
    {
    public:
        static sal_Int32 toINT32(const ::com::sun::star::util::Date&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static sal_Int32 toINT32(const ::com::sun::star::util::Time&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static sal_Int64 toINT64(const ::com::sun::star::util::DateTime&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static sal_Int32 getMsFromTime(const ::com::sun::star::util::Time&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static double    toDouble(const ::com::sun::star::util::Date&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static double    toDouble(const ::com::sun::star::util::Time&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static double    toDouble(const ::com::sun::star::util::DateTime&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static ::com::sun::star::util::Date          toDate(double,const ::com::sun::star::util::Date& =::com::sun::star::util::Date(01,01,1900))
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return ::com::sun::star::util::Date();
        }
        static ::com::sun::star::util::Time          toTime(double)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return ::com::sun::star::util::Time();
        }
        static ::com::sun::star::util::DateTime      toDateTime(double,const ::com::sun::star::util::Date& =::com::sun::star::util::Date(01,01,1900))
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return ::com::sun::star::util::DateTime();
        }
    };
}
#endif // _CONNECTIVITY_DATECONVERSION_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.4.276); FILE MERGED 2008/04/01 10:52:40 thb 1.4.276.2: #i85898# Stripping all external header guards 2008/03/28 15:23:14 rt 1.4.276.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: DateConversion.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_DATECONVERSION_HXX_
#define _CONNECTIVITY_DATECONVERSION_HXX_

#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/Time.hpp>
#include <com/sun/star/util/DateTime.hpp>

namespace connectivity
{
    class DateConversion
    {
    public:
        static sal_Int32 toINT32(const ::com::sun::star::util::Date&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static sal_Int32 toINT32(const ::com::sun::star::util::Time&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static sal_Int64 toINT64(const ::com::sun::star::util::DateTime&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static sal_Int32 getMsFromTime(const ::com::sun::star::util::Time&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static double    toDouble(const ::com::sun::star::util::Date&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static double    toDouble(const ::com::sun::star::util::Time&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static double    toDouble(const ::com::sun::star::util::DateTime&)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return 0;
        }
        static ::com::sun::star::util::Date          toDate(double,const ::com::sun::star::util::Date& =::com::sun::star::util::Date(01,01,1900))
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return ::com::sun::star::util::Date();
        }
        static ::com::sun::star::util::Time          toTime(double)
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return ::com::sun::star::util::Time();
        }
        static ::com::sun::star::util::DateTime      toDateTime(double,const ::com::sun::star::util::Date& =::com::sun::star::util::Date(01,01,1900))
        {
            OSL_ENSURE(0,"Please use DBConversion instead!");
            return ::com::sun::star::util::DateTime();
        }
    };
}
#endif // _CONNECTIVITY_DATECONVERSION_HXX_

<|endoftext|>