<commit_before>/**
 * @file test_llrefcounted
 * @brief unit tests for HttpStatus struct
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef TEST_HTTP_STATUS_H_
#define TEST_HTTP_STATUS_H_

#include "httpcommon.h"

#include <curl/curl.h>
#include <curl/multi.h>

using namespace LLCore;

namespace tut
{

struct HttpStatusTestData
{
	HttpStatusTestData()
		{}
};

typedef test_group<HttpStatusTestData> HttpStatusTestGroupType;
typedef HttpStatusTestGroupType::object HttpStatusTestObjectType;

HttpStatusTestGroupType HttpStatusTestGroup("HttpStatus Tests");

template <> template <>
void HttpStatusTestObjectType::test<1>()
{
	set_test_name("HttpStatus construction");

	// auto allocation fine for this
	HttpStatus status;
	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = 0;

	ensure(bool(status));
	ensure(false == !(status));

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = 0;

	ensure(bool(status));
	ensure(false == !(status));

	status.mType = HttpStatus::LLCORE;
	status.mStatus = HE_SUCCESS;

	ensure(bool(status));
	ensure(false == !(status));

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = -1;

	ensure(false == bool(status));
	ensure(!(status));

	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = CURLE_BAD_DOWNLOAD_RESUME;

	ensure(false == bool(status));
	ensure(!(status));
}

template <> template <>
void HttpStatusTestObjectType::test<2>()
{
	set_test_name("HttpStatus memory structure");
#if LL_WINDOWS
	skip("MAINT-2302: This frequently (though not always) fails on Windows.");
#endif

	// Require that an HttpStatus object can be trivially
	// returned as a function return value in registers.
	// One should fit in an int on all platforms.

	ensure(sizeof(HttpStatus) <= sizeof(int));
}

template <> template <>
void HttpStatusTestObjectType::test<3>()
{
	set_test_name("HttpStatus valid error string conversion");
#if LL_WINDOWS
	skip("MAINT-2302: This frequently (though not always) fails on Windows.");
#endif

	HttpStatus status;
	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = 0;
	std::string msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(msg.empty());

	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = CURLM_OUT_OF_MEMORY;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::LLCORE;
	status.mStatus = HE_SHUTTING_DOWN;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());
}

template <> template <>
void HttpStatusTestObjectType::test<4>()
{
	set_test_name("HttpStatus invalid error string conversion");
#if LL_WINDOWS
	skip("MAINT-2302: This frequently (though not always) fails on Windows.");
#endif

	HttpStatus status;
	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = 32726;
	std::string msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = -470;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::LLCORE;
	status.mStatus = 923;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());
}

template <> template <>
void HttpStatusTestObjectType::test<5>()
{
	set_test_name("HttpStatus equality/inequality testing");
#if LL_WINDOWS
	skip("MAINT-2302: This frequently (though not always) fails on Windows.");
#endif

	// Make certain equality/inequality tests do not pass
	// through the bool conversion.  Distinct successful
	// and error statuses should compare unequal.

	HttpStatus status1(HttpStatus::LLCORE, HE_SUCCESS);
	HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);
	ensure(status1 != status2);

	status1.mType = HttpStatus::LLCORE;
	status1.mStatus = HE_REPLY_ERROR;
	status2.mType = HttpStatus::LLCORE;
	status2.mStatus= HE_SHUTTING_DOWN;
	ensure(status1 != status2);
}

template <> template <>
void HttpStatusTestObjectType::test<6>()
{
	set_test_name("HttpStatus basic HTTP status encoding");
#if LL_WINDOWS
	skip("MAINT-2302: This frequently (though not always) fails on Windows.");
#endif

	HttpStatus status;
	status.mType = 200;
	status.mStatus = HE_SUCCESS;
	std::string msg = status.toString();
	ensure(msg.empty());
	ensure(bool(status));

	// Normally a success but application says error
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(! msg.empty());
	ensure(! bool(status));
	ensure(status.toULong() > 1UL);				// Biggish number, not a bool-to-ulong

	// Same statuses with distinct success/fail are distinct
	status.mType = 200;
	status.mStatus = HE_SUCCESS;
	HttpStatus status2(200, HE_REPLY_ERROR);
	ensure(status != status2);

	// Normally an error but application says okay
	status.mType = 406;
	status.mStatus = HE_SUCCESS;
	msg = status.toString();
	ensure(msg.empty());
	ensure(bool(status));

	// Different statuses but both successful are distinct
	status.mType = 200;
	status.mStatus = HE_SUCCESS;
	status2.mType = 201;
	status2.mStatus = HE_SUCCESS;
	ensure(status != status2);

	// Different statuses but both failed are distinct
	status.mType = 200;
	status.mStatus = HE_REPLY_ERROR;
	status2.mType = 201;
	status2.mStatus = HE_REPLY_ERROR;
	ensure(status != status2);
}

template <> template <>
void HttpStatusTestObjectType::test<7>()
{
	set_test_name("HttpStatus HTTP error text strings");
#if LL_WINDOWS
	skip("MAINT-2302: This frequently (though not always) fails on Windows.");
#endif

	HttpStatus status(100, HE_REPLY_ERROR);
	std::string msg(status.toString());
	ensure(! msg.empty());				// Should be something
	ensure(msg == "Continue");

	status.mStatus = HE_SUCCESS;
	msg = status.toString();
	ensure(msg.empty());				// Success is empty

	status.mType = 199;
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "Unknown error");

	status.mType = 505;					// Last defined string
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "HTTP Version not supported");

	status.mType = 506;					// One beyond
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "Unknown error");

	status.mType = 999;					// Last HTTP status
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "Unknown error");
}

} // end namespace tut

#endif	// TEST_HTTP_STATUS_H

<commit_msg>SH-4190 Reactivate unit tests neutered under MAINT-3202 HttpStatus unit tests have never caused a unit test failure but they do have the word 'error' in their text descriptions which gets picked up by the log processor in TC builds.  So, reactivate the tests and reform the descriptions.<commit_after>/**
 * @file test_llrefcounted
 * @brief unit tests for HttpStatus struct
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012-2013, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef TEST_HTTP_STATUS_H_
#define TEST_HTTP_STATUS_H_

#include "httpcommon.h"

#include <curl/curl.h>
#include <curl/multi.h>

using namespace LLCore;

namespace tut
{

struct HttpStatusTestData
{
	HttpStatusTestData()
		{}
};

typedef test_group<HttpStatusTestData> HttpStatusTestGroupType;
typedef HttpStatusTestGroupType::object HttpStatusTestObjectType;

HttpStatusTestGroupType HttpStatusTestGroup("HttpStatus Tests");

template <> template <>
void HttpStatusTestObjectType::test<1>()
{
	set_test_name("HttpStatus construction");

	// auto allocation fine for this
	HttpStatus status;
	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = 0;

	ensure(bool(status));
	ensure(false == !(status));

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = 0;

	ensure(bool(status));
	ensure(false == !(status));

	status.mType = HttpStatus::LLCORE;
	status.mStatus = HE_SUCCESS;

	ensure(bool(status));
	ensure(false == !(status));

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = -1;

	ensure(false == bool(status));
	ensure(!(status));

	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = CURLE_BAD_DOWNLOAD_RESUME;

	ensure(false == bool(status));
	ensure(!(status));
}

template <> template <>
void HttpStatusTestObjectType::test<2>()
{
	set_test_name("HttpStatus memory structure");

	// Require that an HttpStatus object can be trivially
	// returned as a function return value in registers.
	// One should fit in an int on all platforms.

	ensure(sizeof(HttpStatus) <= sizeof(int));
}

template <> template <>
void HttpStatusTestObjectType::test<3>()
{
	set_test_name("HttpStatus valid status string conversion");

	HttpStatus status;
	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = 0;
	std::string msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(msg.empty());

	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = CURLM_OUT_OF_MEMORY;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::LLCORE;
	status.mStatus = HE_SHUTTING_DOWN;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());
}

template <> template <>
void HttpStatusTestObjectType::test<4>()
{
	set_test_name("HttpStatus invalid status string conversion");

	HttpStatus status;
	status.mType = HttpStatus::EXT_CURL_EASY;
	status.mStatus = 32726;
	std::string msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::EXT_CURL_MULTI;
	status.mStatus = -470;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());

	status.mType = HttpStatus::LLCORE;
	status.mStatus = 923;
	msg = status.toString();
	// std::cout << "Result:  " << msg << std::endl;
	ensure(! msg.empty());
}

template <> template <>
void HttpStatusTestObjectType::test<5>()
{
	set_test_name("HttpStatus equality/inequality testing");

	// Make certain equality/inequality tests do not pass
	// through the bool conversion.  Distinct successful
	// and error statuses should compare unequal.

	HttpStatus status1(HttpStatus::LLCORE, HE_SUCCESS);
	HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);
	ensure(status1 != status2);

	status1.mType = HttpStatus::LLCORE;
	status1.mStatus = HE_REPLY_ERROR;
	status2.mType = HttpStatus::LLCORE;
	status2.mStatus= HE_SHUTTING_DOWN;
	ensure(status1 != status2);
}

template <> template <>
void HttpStatusTestObjectType::test<6>()
{
	set_test_name("HttpStatus basic HTTP status encoding");

	HttpStatus status;
	status.mType = 200;
	status.mStatus = HE_SUCCESS;
	std::string msg = status.toString();
	ensure(msg.empty());
	ensure(bool(status));

	// Normally a success but application says error
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(! msg.empty());
	ensure(! bool(status));
	ensure(status.toULong() > 1UL);				// Biggish number, not a bool-to-ulong

	// Same statuses with distinct success/fail are distinct
	status.mType = 200;
	status.mStatus = HE_SUCCESS;
	HttpStatus status2(200, HE_REPLY_ERROR);
	ensure(status != status2);

	// Normally an error but application says okay
	status.mType = 406;
	status.mStatus = HE_SUCCESS;
	msg = status.toString();
	ensure(msg.empty());
	ensure(bool(status));

	// Different statuses but both successful are distinct
	status.mType = 200;
	status.mStatus = HE_SUCCESS;
	status2.mType = 201;
	status2.mStatus = HE_SUCCESS;
	ensure(status != status2);

	// Different statuses but both failed are distinct
	status.mType = 200;
	status.mStatus = HE_REPLY_ERROR;
	status2.mType = 201;
	status2.mStatus = HE_REPLY_ERROR;
	ensure(status != status2);
}

template <> template <>
void HttpStatusTestObjectType::test<7>()
{
	set_test_name("HttpStatus HTTP status text strings");

	HttpStatus status(100, HE_REPLY_ERROR);
	std::string msg(status.toString());
	ensure(! msg.empty());				// Should be something
	ensure(msg == "Continue");

	status.mStatus = HE_SUCCESS;
	msg = status.toString();
	ensure(msg.empty());				// Success is empty

	status.mType = 199;
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "Unknown error");

	status.mType = 505;					// Last defined string
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "HTTP Version not supported");

	status.mType = 506;					// One beyond
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "Unknown error");

	status.mType = 999;					// Last HTTP status
	status.mStatus = HE_REPLY_ERROR;
	msg = status.toString();
	ensure(msg == "Unknown error");
}

} // end namespace tut

#endif	// TEST_HTTP_STATUS_H

<|endoftext|>


<commit_before>
#pragma once

#include "numerics/fixed_arrays.hpp"

namespace principia {
namespace integrators {
namespace internal_cohen_hubbard_oesterwinter {

using numerics::FixedVector;

// Definition of a Cohen-Hubbard-Oesterwinter formula.  |order_| is the order of
// the approximation, that is, the error on the derivative is h^(order + 1).
// The formula requires |order_| values of the acceleration.  numerators[0]
// corresponds to f"(x₀), numerators[1] to f"(x₋₁), etc.
// TODO(phl): This struct shows up in many places.  Factor it out.
template<int order_>
struct CohenHubbardOesterwinter final {
  static constexpr int order = order_;
  FixedVector<double, order> numerators;
  double denominator;
};

}  // namespace internal_cohen_hubbard_oesterwinter

using internal_cohen_hubbard_oesterwinter::CohenHubbardOesterwinter;

template<int order>
CohenHubbardOesterwinter<order> const& CohenHubbardOesterwinterOrder();

}  // namespace integrators
}  // namespace principia

#include "integrators/backward_difference_body.hpp"
<commit_msg>After egg's review.<commit_after>
#pragma once

#include "numerics/fixed_arrays.hpp"

namespace principia {
namespace integrators {
namespace internal_cohen_hubbard_oesterwinter {

using numerics::FixedVector;

// Definition of a modified Cohen-Hubbard-Oesterwinter formula, see Cohen,
// Hubbard, Oesterwinter (1973), Astronomical papers prepared for the use of the
// American ephemeris and nautical almanac Volume XXII Part I, p. 21.  Our
// formula is:
//   f′(x₀) ≅ f(x₀) - f(x₋₁) + h Σ(ηᵢ f″(x₋ᵢ))
// where the sum is for i going from 0 to order_ - 1.  The ηᵢ are computed
// using Mathematica, see cohen_hubbard_oesterwinter.wl.
// |order_| is the order of the approximation, that is, the error on the
// derivative is 𝒪(h^(order_ + 1)).  The formula requires |order_| values of the
// acceleration.  numerators[0] corresponds to f″(x₀), numerators[1] to f″(x₋₁),
// etc.
// TODO(phl): This struct shows up in many places.  Factor it out.
template<int order_>
struct CohenHubbardOesterwinter final {
  static constexpr int order = order_;
  FixedVector<double, order> numerators;
  double denominator;
};

}  // namespace internal_cohen_hubbard_oesterwinter

using internal_cohen_hubbard_oesterwinter::CohenHubbardOesterwinter;

template<int order>
CohenHubbardOesterwinter<order> const& CohenHubbardOesterwinterOrder();

}  // namespace integrators
}  // namespace principia

#include "integrators/backward_difference_body.hpp"
<|endoftext|>


<commit_before>/* Copyright (c) 2010-2011 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any purpose
 * with or without fee is hereby granted, provided that the above copyright
 * notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "TestUtil.h"
#include "MockFastTransport.h"
#include "MockSyscall.h"
#include "Tub.h"
#include "UdpDriver.h"

namespace RAMCloud {
class UdpDriverTest : public CppUnit::TestFixture {
    CPPUNIT_TEST_SUITE(UdpDriverTest);
    CPPUNIT_TEST(test_basics);
    CPPUNIT_TEST(test_constructor_errorInSocketCall);
    CPPUNIT_TEST(test_constructor_socketInUse);
    CPPUNIT_TEST(test_destructor_closeSocket);
    CPPUNIT_TEST(test_sendPacket_headerEmpty);
    CPPUNIT_TEST(test_sendPacket_payloadEmpty);
    CPPUNIT_TEST(test_sendPacket_multipleChunks);
    CPPUNIT_TEST(test_sendPacket_errorInSend);
    CPPUNIT_TEST(test_ReadHandler_errorInRecv);
    CPPUNIT_TEST(test_ReadHandler_noPacketAvailable);
    CPPUNIT_TEST(test_ReadHandler_multiplePackets);
    CPPUNIT_TEST_SUITE_END();

  public:
    string exceptionMessage;
    ServiceLocator *serverLocator;
    IpAddress *serverAddress;
    UdpDriver *server;
    UdpDriver *client;
    MockSyscall* sys;
    Syscall *savedSyscall;
    TestLog::Enable* logEnabler;
    MockFastTransport *clientTransport, *serverTransport;

    UdpDriverTest()
        : exceptionMessage()
        , serverLocator(NULL)
        , serverAddress(NULL)
        , server(NULL)
        , client(NULL)
        , sys(NULL)
        , savedSyscall(NULL)
        , logEnabler(NULL)
        , clientTransport(NULL)
        , serverTransport(NULL)
    {}

    void setUp() {
        savedSyscall = UdpDriver::sys;
        sys = new MockSyscall();
        UdpDriver::sys = sys;
        exceptionMessage = "no exception";
        serverLocator = new ServiceLocator("udp: host=localhost, port=8100");
        serverAddress = new IpAddress(*serverLocator);
        server = new UdpDriver(serverLocator);
        client = new UdpDriver;
        logEnabler = new TestLog::Enable();
        clientTransport = new MockFastTransport(client);
        serverTransport = new MockFastTransport(server);
    }

    void tearDown() {
        delete serverLocator;
        serverLocator = NULL;
        delete serverAddress;
        serverAddress = NULL;
        // Note: deleting the transport deletes the driver implicitly.
        if (serverTransport != NULL) {
            delete serverTransport;
            serverTransport = NULL;
            server = NULL;
        }
        delete clientTransport;
        clientTransport = NULL;
        client = NULL;
        delete sys;
        sys = NULL;
        UdpDriver::sys = savedSyscall;
        delete logEnabler;
    }

    void sendMessage(UdpDriver *driver, IpAddress *address,
            const char *header, const char *payload) {
        Buffer message;
        Buffer::Chunk::appendToBuffer(&message, payload,
                                      downCast<uint32_t>(strlen(payload)));
        Buffer::Iterator iterator(message);
        driver->sendPacket(address, header, downCast<uint32_t>(strlen(header)),
                           &iterator);
    }

    // Used to wait for data to arrive on a driver by invoking the
    // dispatcher's polling loop; gives up if a long time goes by with
    // no data.
    const char *receivePacket(MockFastTransport *transport) {
        transport->packetData.clear();
        uint64_t start = rdtsc();
        while (true) {
            dispatch->poll();
            if (transport->packetData.size() != 0) {
                return transport->packetData.c_str();
            }
            if (cyclesToSeconds(rdtsc() - start) > .1) {
                return "no packet arrived";
            }
        }
    }

    void test_basics() {
        // Send a packet from a client-style driver to a server-style
        // driver.
        Buffer message;
        const char *testString = "This is a sample message";
        Buffer::Chunk::appendToBuffer(&message, testString,
                downCast<uint32_t>(strlen(testString)));
        Buffer::Iterator iterator(message);
        client->sendPacket(serverAddress, "header:", 7, &iterator);
        CPPUNIT_ASSERT_EQUAL("header:This is a sample message",
                receivePacket(serverTransport));

        // Send a response back in the other direction.
        message.reset();
        Buffer::Chunk::appendToBuffer(&message, "response", 8);
        Buffer::Iterator iterator2(message);
        server->sendPacket(serverTransport->sender, "h:", 2, &iterator2);
        CPPUNIT_ASSERT_EQUAL("h:response", receivePacket(clientTransport));
    }

    void test_constructor_errorInSocketCall() {
        sys->socketErrno = EPERM;
        try {
            UdpDriver server2(serverLocator);
        } catch (DriverException& e) {
            exceptionMessage = e.message;
        }
        CPPUNIT_ASSERT_EQUAL("UdpDriver couldn't create socket: "
                    "Operation not permitted", exceptionMessage);
    }

    void test_constructor_socketInUse() {
        try {
            UdpDriver server2(serverLocator);
        } catch (DriverException& e) {
            exceptionMessage = e.message;
        }
        CPPUNIT_ASSERT_EQUAL("UdpDriver couldn't bind to locator "
                "'udp: host=localhost, port=8100': Address already in use",
                exceptionMessage);
    }

    void test_destructor_closeSocket() {
        // If the socket isn't closed, we won't be able to create another
        // UdpDriver that binds to the same socket.
        delete serverTransport;
        serverTransport = NULL;
        try {
            server = new UdpDriver(serverLocator);
            serverTransport = new MockFastTransport(server);
        } catch (DriverException& e) {
            exceptionMessage = e.message;
        }
        CPPUNIT_ASSERT_EQUAL("no exception", exceptionMessage);
    }

    void test_sendPacket_headerEmpty() {
        Buffer message;
        Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
        Buffer::Iterator iterator(message);
        client->sendPacket(serverAddress, "", 0, &iterator);
        CPPUNIT_ASSERT_EQUAL("xyzzy", receivePacket(serverTransport));
    }

    void test_sendPacket_payloadEmpty() {
        Buffer message;
        Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
        Buffer::Iterator iterator(message);
        client->sendPacket(serverAddress, "header:", 7, &iterator);
        CPPUNIT_ASSERT_EQUAL("header:xyzzy", receivePacket(serverTransport));
    }

    void test_sendPacket_multipleChunks() {
        Buffer message;
        Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
        Buffer::Chunk::appendToBuffer(&message, "0123456789", 10);
        Buffer::Chunk::appendToBuffer(&message, "abc", 3);
        Buffer::Iterator iterator(message, 1, 23);
        client->sendPacket(serverAddress, "header:", 7, &iterator);
        CPPUNIT_ASSERT_EQUAL("header:yzzy0123456789abc",
                receivePacket(serverTransport));
    }

    void test_sendPacket_errorInSend() {
        sys->sendmsgErrno = EPERM;
        Buffer message;
        Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
        Buffer::Iterator iterator(message);
        try {
            client->sendPacket(serverAddress, "header:", 7, &iterator);
        } catch (DriverException& e) {
            exceptionMessage = e.message;
        }
        CPPUNIT_ASSERT_EQUAL("UdpDriver error sending to socket: "
                "Operation not permitted", exceptionMessage);
    }

    void test_ReadHandler_errorInRecv() {
        sys->recvfromErrno = EPERM;
        Driver::Received received;
        try {
            server->readHandler->handleFileEvent(
                    Dispatch::FileEvent::READABLE);
        } catch (DriverException& e) {
            exceptionMessage = e.message;
        }
        CPPUNIT_ASSERT_EQUAL("UdpDriver error receiving from socket: "
                "Operation not permitted", exceptionMessage);
    }

    void test_ReadHandler_noPacketAvailable() {
        server->readHandler->handleFileEvent(
                Dispatch::FileEvent::READABLE);
        CPPUNIT_ASSERT_EQUAL("", serverTransport->packetData);
    }

    void test_ReadHandler_multiplePackets() {
        sendMessage(client, serverAddress, "header:", "first");
        sendMessage(client, serverAddress, "header:", "second");
        sendMessage(client, serverAddress, "header:", "third");
        CPPUNIT_ASSERT_EQUAL("header:first", receivePacket(serverTransport));
        CPPUNIT_ASSERT_EQUAL("header:second", receivePacket(serverTransport));
        CPPUNIT_ASSERT_EQUAL("header:third", receivePacket(serverTransport));
    }

  private:
    DISALLOW_COPY_AND_ASSIGN(UdpDriverTest);
};
CPPUNIT_TEST_SUITE_REGISTRATION(UdpDriverTest);

}  // namespace RAMCloud
<commit_msg>Convert UdpDriverTest to gtest.<commit_after>/* Copyright (c) 2010-2011 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any purpose
 * with or without fee is hereby granted, provided that the above copyright
 * notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "TestUtil.h"
#include "MockFastTransport.h"
#include "MockSyscall.h"
#include "Tub.h"
#include "UdpDriver.h"

namespace RAMCloud {
class UdpDriverTest : public ::testing::Test {
  public:
    string exceptionMessage;
    ServiceLocator *serverLocator;
    IpAddress *serverAddress;
    UdpDriver *server;
    UdpDriver *client;
    MockSyscall* sys;
    Syscall *savedSyscall;
    TestLog::Enable* logEnabler;
    MockFastTransport *clientTransport, *serverTransport;

    UdpDriverTest()
        : exceptionMessage()
        , serverLocator(NULL)
        , serverAddress(NULL)
        , server(NULL)
        , client(NULL)
        , sys(NULL)
        , savedSyscall(NULL)
        , logEnabler(NULL)
        , clientTransport(NULL)
        , serverTransport(NULL)
    {
        savedSyscall = UdpDriver::sys;
        sys = new MockSyscall();
        UdpDriver::sys = sys;
        exceptionMessage = "no exception";
        serverLocator = new ServiceLocator("udp: host=localhost, port=8100");
        serverAddress = new IpAddress(*serverLocator);
        server = new UdpDriver(serverLocator);
        client = new UdpDriver;
        logEnabler = new TestLog::Enable();
        clientTransport = new MockFastTransport(client);
        serverTransport = new MockFastTransport(server);
    }

    ~UdpDriverTest() {
        delete serverLocator;
        serverLocator = NULL;
        delete serverAddress;
        serverAddress = NULL;
        // Note: deleting the transport deletes the driver implicitly.
        if (serverTransport != NULL) {
            delete serverTransport;
            serverTransport = NULL;
            server = NULL;
        }
        delete clientTransport;
        clientTransport = NULL;
        client = NULL;
        delete sys;
        sys = NULL;
        UdpDriver::sys = savedSyscall;
        delete logEnabler;
    }

    void sendMessage(UdpDriver *driver, IpAddress *address,
            const char *header, const char *payload) {
        Buffer message;
        Buffer::Chunk::appendToBuffer(&message, payload,
                                      downCast<uint32_t>(strlen(payload)));
        Buffer::Iterator iterator(message);
        driver->sendPacket(address, header, downCast<uint32_t>(strlen(header)),
                           &iterator);
    }

    // Used to wait for data to arrive on a driver by invoking the
    // dispatcher's polling loop; gives up if a long time goes by with
    // no data.
    const char *receivePacket(MockFastTransport *transport) {
        transport->packetData.clear();
        uint64_t start = rdtsc();
        while (true) {
            dispatch->poll();
            if (transport->packetData.size() != 0) {
                return transport->packetData.c_str();
            }
            if (cyclesToSeconds(rdtsc() - start) > .1) {
                return "no packet arrived";
            }
        }
    }

  private:
    DISALLOW_COPY_AND_ASSIGN(UdpDriverTest);
};

TEST_F(UdpDriverTest, basics) {
    // Send a packet from a client-style driver to a server-style
    // driver.
    Buffer message;
    const char *testString = "This is a sample message";
    Buffer::Chunk::appendToBuffer(&message, testString,
            downCast<uint32_t>(strlen(testString)));
    Buffer::Iterator iterator(message);
    client->sendPacket(serverAddress, "header:", 7, &iterator);
    EXPECT_STREQ("header:This is a sample message",
            receivePacket(serverTransport));

    // Send a response back in the other direction.
    message.reset();
    Buffer::Chunk::appendToBuffer(&message, "response", 8);
    Buffer::Iterator iterator2(message);
    server->sendPacket(serverTransport->sender, "h:", 2, &iterator2);
    EXPECT_STREQ("h:response", receivePacket(clientTransport));
}

TEST_F(UdpDriverTest, constructor_errorInSocketCall) {
    sys->socketErrno = EPERM;
    try {
        UdpDriver server2(serverLocator);
    } catch (DriverException& e) {
        exceptionMessage = e.message;
    }
    EXPECT_EQ("UdpDriver couldn't create socket: "
                "Operation not permitted", exceptionMessage);
}

TEST_F(UdpDriverTest, constructor_socketInUse) {
    try {
        UdpDriver server2(serverLocator);
    } catch (DriverException& e) {
        exceptionMessage = e.message;
    }
    EXPECT_EQ("UdpDriver couldn't bind to locator "
            "'udp: host=localhost, port=8100': Address already in use",
            exceptionMessage);
}

TEST_F(UdpDriverTest, destructor_closeSocket) {
    // If the socket isn't closed, we won't be able to create another
    // UdpDriver that binds to the same socket.
    delete serverTransport;
    serverTransport = NULL;
    try {
        server = new UdpDriver(serverLocator);
        serverTransport = new MockFastTransport(server);
    } catch (DriverException& e) {
        exceptionMessage = e.message;
    }
    EXPECT_EQ("no exception", exceptionMessage);
}

TEST_F(UdpDriverTest, sendPacket_headerEmpty) {
    Buffer message;
    Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
    Buffer::Iterator iterator(message);
    client->sendPacket(serverAddress, "", 0, &iterator);
    EXPECT_STREQ("xyzzy", receivePacket(serverTransport));
}

TEST_F(UdpDriverTest, sendPacket_payloadEmpty) {
    Buffer message;
    Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
    Buffer::Iterator iterator(message);
    client->sendPacket(serverAddress, "header:", 7, &iterator);
    EXPECT_STREQ("header:xyzzy", receivePacket(serverTransport));
}

TEST_F(UdpDriverTest, sendPacket_multipleChunks) {
    Buffer message;
    Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
    Buffer::Chunk::appendToBuffer(&message, "0123456789", 10);
    Buffer::Chunk::appendToBuffer(&message, "abc", 3);
    Buffer::Iterator iterator(message, 1, 23);
    client->sendPacket(serverAddress, "header:", 7, &iterator);
    EXPECT_STREQ("header:yzzy0123456789abc",
            receivePacket(serverTransport));
}

TEST_F(UdpDriverTest, sendPacket_errorInSend) {
    sys->sendmsgErrno = EPERM;
    Buffer message;
    Buffer::Chunk::appendToBuffer(&message, "xyzzy", 5);
    Buffer::Iterator iterator(message);
    try {
        client->sendPacket(serverAddress, "header:", 7, &iterator);
    } catch (DriverException& e) {
        exceptionMessage = e.message;
    }
    EXPECT_EQ("UdpDriver error sending to socket: "
            "Operation not permitted", exceptionMessage);
}

TEST_F(UdpDriverTest, ReadHandler_errorInRecv) {
    sys->recvfromErrno = EPERM;
    Driver::Received received;
    try {
        server->readHandler->handleFileEvent(
                Dispatch::FileEvent::READABLE);
    } catch (DriverException& e) {
        exceptionMessage = e.message;
    }
    EXPECT_EQ("UdpDriver error receiving from socket: "
            "Operation not permitted", exceptionMessage);
}

TEST_F(UdpDriverTest, ReadHandler_noPacketAvailable) {
    server->readHandler->handleFileEvent(
            Dispatch::FileEvent::READABLE);
    EXPECT_EQ("", serverTransport->packetData);
}

TEST_F(UdpDriverTest, ReadHandler_multiplePackets) {
    sendMessage(client, serverAddress, "header:", "first");
    sendMessage(client, serverAddress, "header:", "second");
    sendMessage(client, serverAddress, "header:", "third");
    EXPECT_STREQ("header:first", receivePacket(serverTransport));
    EXPECT_STREQ("header:second", receivePacket(serverTransport));
    EXPECT_STREQ("header:third", receivePacket(serverTransport));
}

}  // namespace RAMCloud
<|endoftext|>


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

// Interface header.
#include "projectbuilder.h"

// appleseed-max headers.
#include "maxsceneentities.h"
#include "utilities.h"

// appleseed.renderer headers.
#include "renderer/api/camera.h"
#include "renderer/api/environment.h"
#include "renderer/api/frame.h"
#include "renderer/api/object.h"
#include "renderer/api/project.h"
#include "renderer/api/scene.h"
#include "renderer/api/utility.h"

// appleseed.foundation headers.
#include "foundation/math/transform.h"
#include "foundation/platform/compiler.h"
#include "foundation/utility/containers/dictionary.h"

// 3ds Max headers.
#include <bitmap.h>
#include <object.h>
#include <render.h>
#include <triobj.h>

// Standard headers.
#include <cassert>
#include <cstddef>
#include <limits>
#include <string>
#include <vector>

namespace asf = foundation;
namespace asr = renderer;

namespace
{
    asf::auto_release_ptr<asr::Camera> build_camera(
        INode*                  view_node,
        const ViewParams&       view_params,
        Bitmap*                 bitmap,
        const TimeValue         time)
    {
        asr::ParamArray params;

        if (view_params.projType == PROJ_PERSPECTIVE)
        {
            params.insert("film_dimensions", "0.024892 0.018669");
            params.insert("focal_length", "0.035");
        }
        else
        {
            assert(view_params.projType == PROJ_PARALLEL);

            const float ViewDefaultWidth = 400.0f;
            const float a = bitmap->Aspect();
            const float aspect = static_cast<float>(bitmap->Height()) / bitmap->Width();
            const float hscale = bitmap->Width() / (ViewDefaultWidth * view_params.zoom);
            const float vscale = hscale * aspect;
            const float film_width = ViewDefaultWidth * view_params.zoom;
            const float film_height = aspect * film_width;
            params.insert("film_dimensions", make_vec_string(film_width, film_height));
        }

        asf::Matrix4d camera_matrix = max_to_as(Inverse(view_params.affineTM));

        if (view_node)
        {
            const ObjectState& os = view_node->EvalWorldState(time);
            switch (os.obj->SuperClassID())
            {
              case CAMERA_CLASS_ID:
                {
                    CameraObject* cam = static_cast<CameraObject*>(os.obj);

                    Interval validity_interval;
                    validity_interval.SetInfinite();

                    Matrix3 cam_to_world = view_node->GetObjTMAfterWSM(time, &validity_interval);
                    cam_to_world.NoScale();
                    camera_matrix = max_to_as(cam_to_world);

                    CameraState cam_state;
                    cam->EvalCameraState(time, validity_interval, &cam_state);

                    if (cam_state.manualClip)
                        params.insert("near_z", cam_state.hither);
                }
                break;

              case LIGHT_CLASS_ID:
                {
                    // todo: implement.
                }
                break;

              default:
                assert(!"Unexpected super class ID  for camera.");
            }
        }

        asf::auto_release_ptr<renderer::Camera> camera =
            view_params.projType == PROJ_PERSPECTIVE
                ? asr::PinholeCameraFactory().create("camera", params)
                : asr::OrthographicCameraFactory().create("camera", params);

        camera->transform_sequence().set_transform(
            0.0, asf::Transformd::from_local_to_parent(camera_matrix));

        return camera;
    }

    TriObject* get_tri_object_from_node(
        const ObjectState&      object_state,
        const TimeValue         time,
        bool&                   must_delete)
    {
        assert(object_state.obj);

        must_delete = false;

        const Class_ID TriObjectClassID(TRIOBJ_CLASS_ID, 0);

        if (!object_state.obj->CanConvertToType(TriObjectClassID))
            return 0;

        TriObject* tri_object = static_cast<TriObject*>(object_state.obj->ConvertToType(time, TriObjectClassID));
        must_delete = tri_object != object_state.obj;

        return tri_object;
    }

    void add_object(
        asr::Assembly&          assembly,
        INode*                  node,
        const TimeValue         time)
    {
        // Retrieve the name of the referenced object.
        Object* max_object = node->GetObjectRef();
        const std::string object_name = utf8_encode(max_object->GetObjectName());

        // Create the object if it doesn't already exist in the appleseed scene.
        if (assembly.objects().get_by_name(object_name.c_str()) == 0)
        {
            // Retrieve the ObjectState at the desired time.
            const ObjectState object_state = node->EvalWorldState(time);

            // Convert the object to a TriObject.
            bool must_delete_tri_object;
            TriObject* tri_object = get_tri_object_from_node(object_state, time, must_delete_tri_object);
            if (tri_object == 0)
            {
                // todo: emit a message?
                return;
            }

            // Create a new mesh object.
            asf::auto_release_ptr<asr::MeshObject> object(
                asr::MeshObjectFactory::create(object_name.c_str(), asr::ParamArray()));
            {
                Mesh& mesh = tri_object->GetMesh();

                // Copy vertices to the mesh object.
                object->reserve_vertices(mesh.getNumVerts());
                for (int i = 0, e = mesh.getNumVerts(); i < e; ++i)
                {
                    const Point3& v = mesh.getVert(i);
                    //object->push_vertex(max_to_as(v));
                    object->push_vertex(asf::Vector3d(v.x, v.y, v.z));
                }

                // Copy triangles to mesh object.
                object->reserve_triangles(mesh.getNumFaces());
                for (int i = 0, e = mesh.getNumFaces(); i < e; ++i)
                {
                    Face& face = mesh.faces[i];
                    const asr::Triangle triangle(
                        face.getVert(0),
                        face.getVert(1),
                        face.getVert(2));
                    object->push_triangle(triangle);
                }

                // Delete the TriObject if necessary.
                if (must_delete_tri_object)
                    tri_object->DeleteMe();
            }

            // Insert the object into the assembly.
            assembly.objects().insert(asf::auto_release_ptr<asr::Object>(object));
        }

        // Figure out a unique name for this instance.
        std::string instance_name = utf8_encode(node->GetName());
        if (assembly.object_instances().get_by_name(instance_name.c_str()) != 0)
            instance_name = asr::make_unique_name(instance_name, assembly.object_instances());

        // Create an instance of the object and insert it into the assembly.
        assembly.object_instances().insert(
            asr::ObjectInstanceFactory::create(
                instance_name.c_str(),
                asr::ParamArray(),
                object_name.c_str(),
                asf::Transformd::from_local_to_parent(
                    max_to_as(node->GetObjTMAfterWSM(time))),
                asf::StringDictionary()));
    }

    void populate_assembly(
        asr::Assembly&          assembly,
        const MaxSceneEntities& entities,
        const TimeValue         time)
    {
        for (size_t i = 0, e = entities.m_instances.size(); i < e; ++i)
            add_object(assembly, entities.m_instances[i], time);
    }
}

asf::auto_release_ptr<asr::Project> build_project(
    const MaxSceneEntities&     entities,
    INode*                      view_node,
    const ViewParams&           view_params,
    Bitmap*                     bitmap,
    const TimeValue             time)
{
    // Create an empty project.
    asf::auto_release_ptr<asr::Project> project(
        asr::ProjectFactory::create("project"));

    // Add default configurations to the project.
    project->add_default_configurations();

    // Set the number of samples.
    project->configurations()
        .get_by_name("final")->get_parameters()
            .insert_path("uniform_pixel_renderer.samples", "1");

    // Create a scene.
    asf::auto_release_ptr<asr::Scene> scene(asr::SceneFactory::create());

    // Create an assembly.
    asf::auto_release_ptr<asr::Assembly> assembly(
        asr::AssemblyFactory().create("assembly", asr::ParamArray()));

    // Populate the assembly with entities from the 3ds Max scene.
    populate_assembly(assembly.ref(), entities, time);

    // Create an instance of the assembly and insert it into the scene.
    asf::auto_release_ptr<asr::AssemblyInstance> assembly_instance(
        asr::AssemblyInstanceFactory::create(
            "assembly_inst",
            asr::ParamArray(),
            "assembly"));
    assembly_instance
        ->transform_sequence()
            .set_transform(0.0, asf::Transformd::identity());
    scene->assembly_instances().insert(assembly_instance);

    // Insert the assembly into the scene.
    scene->assemblies().insert(assembly);

    // Create a default environment and bind it to the scene.
    scene->set_environment(
        asr::EnvironmentFactory::create("environment", asr::ParamArray()));

    // Create a camera.
    scene->set_camera(
        build_camera(
            view_node,
            view_params,
            bitmap,
            time));

    // Create a frame and bind it to the project.
    project->set_frame(
        asr::FrameFactory::create(
            "beauty",
            asr::ParamArray()
                .insert("camera", scene->get_camera()->get_name())
                .insert("resolution", make_vec_string(bitmap->Width(), bitmap->Height()))
                .insert("color_space", "linear_rgb")));

    // Bind the scene to the project.
    project->set_scene(scene);

    return project;
}
<commit_msg>Fix film dimensions and horizontal FOV for perspective renders<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "projectbuilder.h"

// appleseed-max headers.
#include "maxsceneentities.h"
#include "utilities.h"

// appleseed.renderer headers.
#include "renderer/api/camera.h"
#include "renderer/api/environment.h"
#include "renderer/api/frame.h"
#include "renderer/api/object.h"
#include "renderer/api/project.h"
#include "renderer/api/scene.h"
#include "renderer/api/utility.h"

// appleseed.foundation headers.
#include "foundation/math/scalar.h"
#include "foundation/math/transform.h"
#include "foundation/platform/compiler.h"
#include "foundation/utility/containers/dictionary.h"

// 3ds Max headers.
#include <bitmap.h>
#include <object.h>
#include <render.h>
#include <triobj.h>

// Standard headers.
#include <cassert>
#include <cstddef>
#include <limits>
#include <string>
#include <vector>

namespace asf = foundation;
namespace asr = renderer;

namespace
{
    asf::auto_release_ptr<asr::Camera> build_camera(
        INode*                  view_node,
        const ViewParams&       view_params,
        Bitmap*                 bitmap,
        const TimeValue         time)
    {
        asr::ParamArray params;

        if (view_params.projType == PROJ_PERSPECTIVE)
        {
            params.insert("film_dimensions", make_vec_string(bitmap->Width(), bitmap->Height()));
            params.insert("horizontal_fov", asf::rad_to_deg(view_params.fov));
        }
        else
        {
            assert(view_params.projType == PROJ_PARALLEL);

            const float ViewDefaultWidth = 400.0f;
            const float a = bitmap->Aspect();
            const float aspect = static_cast<float>(bitmap->Height()) / bitmap->Width();
            const float hscale = bitmap->Width() / (ViewDefaultWidth * view_params.zoom);
            const float vscale = hscale * aspect;
            const float film_width = ViewDefaultWidth * view_params.zoom;
            const float film_height = aspect * film_width;
            params.insert("film_dimensions", make_vec_string(film_width, film_height));
        }

        asf::Matrix4d camera_matrix = max_to_as(Inverse(view_params.affineTM));

        if (view_node)
        {
            const ObjectState& os = view_node->EvalWorldState(time);
            switch (os.obj->SuperClassID())
            {
              case CAMERA_CLASS_ID:
                {
                    CameraObject* cam = static_cast<CameraObject*>(os.obj);

                    Interval validity_interval;
                    validity_interval.SetInfinite();

                    Matrix3 cam_to_world = view_node->GetObjTMAfterWSM(time, &validity_interval);
                    cam_to_world.NoScale();
                    camera_matrix = max_to_as(cam_to_world);

                    CameraState cam_state;
                    cam->EvalCameraState(time, validity_interval, &cam_state);

                    if (cam_state.manualClip)
                        params.insert("near_z", cam_state.hither);
                }
                break;

              case LIGHT_CLASS_ID:
                {
                    // todo: implement.
                }
                break;

              default:
                assert(!"Unexpected super class ID  for camera.");
            }
        }

        asf::auto_release_ptr<renderer::Camera> camera =
            view_params.projType == PROJ_PERSPECTIVE
                ? asr::PinholeCameraFactory().create("camera", params)
                : asr::OrthographicCameraFactory().create("camera", params);

        camera->transform_sequence().set_transform(
            0.0, asf::Transformd::from_local_to_parent(camera_matrix));

        return camera;
    }

    TriObject* get_tri_object_from_node(
        const ObjectState&      object_state,
        const TimeValue         time,
        bool&                   must_delete)
    {
        assert(object_state.obj);

        must_delete = false;

        const Class_ID TriObjectClassID(TRIOBJ_CLASS_ID, 0);

        if (!object_state.obj->CanConvertToType(TriObjectClassID))
            return 0;

        TriObject* tri_object = static_cast<TriObject*>(object_state.obj->ConvertToType(time, TriObjectClassID));
        must_delete = tri_object != object_state.obj;

        return tri_object;
    }

    void add_object(
        asr::Assembly&          assembly,
        INode*                  node,
        const TimeValue         time)
    {
        // Retrieve the name of the referenced object.
        Object* max_object = node->GetObjectRef();
        const std::string object_name = utf8_encode(max_object->GetObjectName());

        // Create the object if it doesn't already exist in the appleseed scene.
        if (assembly.objects().get_by_name(object_name.c_str()) == 0)
        {
            // Retrieve the ObjectState at the desired time.
            const ObjectState object_state = node->EvalWorldState(time);

            // Convert the object to a TriObject.
            bool must_delete_tri_object;
            TriObject* tri_object = get_tri_object_from_node(object_state, time, must_delete_tri_object);
            if (tri_object == 0)
            {
                // todo: emit a message?
                return;
            }

            // Create a new mesh object.
            asf::auto_release_ptr<asr::MeshObject> object(
                asr::MeshObjectFactory::create(object_name.c_str(), asr::ParamArray()));
            {
                Mesh& mesh = tri_object->GetMesh();

                // Copy vertices to the mesh object.
                object->reserve_vertices(mesh.getNumVerts());
                for (int i = 0, e = mesh.getNumVerts(); i < e; ++i)
                {
                    const Point3& v = mesh.getVert(i);
                    //object->push_vertex(max_to_as(v));
                    object->push_vertex(asf::Vector3d(v.x, v.y, v.z));
                }

                // Copy triangles to mesh object.
                object->reserve_triangles(mesh.getNumFaces());
                for (int i = 0, e = mesh.getNumFaces(); i < e; ++i)
                {
                    Face& face = mesh.faces[i];
                    const asr::Triangle triangle(
                        face.getVert(0),
                        face.getVert(1),
                        face.getVert(2));
                    object->push_triangle(triangle);
                }

                // Delete the TriObject if necessary.
                if (must_delete_tri_object)
                    tri_object->DeleteMe();
            }

            // Insert the object into the assembly.
            assembly.objects().insert(asf::auto_release_ptr<asr::Object>(object));
        }

        // Figure out a unique name for this instance.
        std::string instance_name = utf8_encode(node->GetName());
        if (assembly.object_instances().get_by_name(instance_name.c_str()) != 0)
            instance_name = asr::make_unique_name(instance_name, assembly.object_instances());

        // Create an instance of the object and insert it into the assembly.
        assembly.object_instances().insert(
            asr::ObjectInstanceFactory::create(
                instance_name.c_str(),
                asr::ParamArray(),
                object_name.c_str(),
                asf::Transformd::from_local_to_parent(
                    max_to_as(node->GetObjTMAfterWSM(time))),
                asf::StringDictionary()));
    }

    void populate_assembly(
        asr::Assembly&          assembly,
        const MaxSceneEntities& entities,
        const TimeValue         time)
    {
        for (size_t i = 0, e = entities.m_instances.size(); i < e; ++i)
            add_object(assembly, entities.m_instances[i], time);
    }
}

asf::auto_release_ptr<asr::Project> build_project(
    const MaxSceneEntities&     entities,
    INode*                      view_node,
    const ViewParams&           view_params,
    Bitmap*                     bitmap,
    const TimeValue             time)
{
    // Create an empty project.
    asf::auto_release_ptr<asr::Project> project(
        asr::ProjectFactory::create("project"));

    // Add default configurations to the project.
    project->add_default_configurations();

    // Set the number of samples.
    project->configurations()
        .get_by_name("final")->get_parameters()
            .insert_path("uniform_pixel_renderer.samples", "1");

    // Create a scene.
    asf::auto_release_ptr<asr::Scene> scene(asr::SceneFactory::create());

    // Create an assembly.
    asf::auto_release_ptr<asr::Assembly> assembly(
        asr::AssemblyFactory().create("assembly", asr::ParamArray()));

    // Populate the assembly with entities from the 3ds Max scene.
    populate_assembly(assembly.ref(), entities, time);

    // Create an instance of the assembly and insert it into the scene.
    asf::auto_release_ptr<asr::AssemblyInstance> assembly_instance(
        asr::AssemblyInstanceFactory::create(
            "assembly_inst",
            asr::ParamArray(),
            "assembly"));
    assembly_instance
        ->transform_sequence()
            .set_transform(0.0, asf::Transformd::identity());
    scene->assembly_instances().insert(assembly_instance);

    // Insert the assembly into the scene.
    scene->assemblies().insert(assembly);

    // Create a default environment and bind it to the scene.
    scene->set_environment(
        asr::EnvironmentFactory::create("environment", asr::ParamArray()));

    // Create a camera.
    scene->set_camera(
        build_camera(
            view_node,
            view_params,
            bitmap,
            time));

    // Create a frame and bind it to the project.
    project->set_frame(
        asr::FrameFactory::create(
            "beauty",
            asr::ParamArray()
                .insert("camera", scene->get_camera()->get_name())
                .insert("resolution", make_vec_string(bitmap->Width(), bitmap->Height()))
                .insert("color_space", "linear_rgb")));

    // Bind the scene to the project.
    project->set_scene(scene);

    return project;
}
<|endoftext|>


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

#include "Version.hpp"

namespace werk
{

const char *getVersion() {
	return WERK_VERSION;
}

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

#include "Version.hpp"

namespace werk
{

const char *getVersion()
{
	return WERK_VERSION;
}

}
<|endoftext|>


<commit_before>#include <string>
#include <stdlib.h>

#include "../USB.h"

extern HINSTANCE hInst;
std::wstring IniDir;
std::wstring LogDir;

void CALLBACK USBsetSettingsDir( const char* dir )
{
	fprintf(stderr, "USBsetSettingsDir: %s\n", dir);
	wchar_t dst[4096] = {0};
	mbstowcs(dst, dir, ARRAYSIZE(dst));
	IniDir = dst;
}

void CALLBACK USBsetLogDir( const char* dir )
{
	printf("USBsetLogDir: %s\n", dir);
	wchar_t dst[4096] = {0};
	mbstowcs(dst, dir, ARRAYSIZE(dst));
	LogDir = dst;
}

void GetIniFile(std::wstring &iniFile)
{
	iniFile.clear();
	if(!IniDir.length()) {
		TCHAR tmp[MAX_PATH] = {0};
		GetModuleFileName(GetModuleHandle((LPWSTR)hInst), tmp, MAX_PATH);

		std::wstring path(tmp);
		unsigned last = path.find_last_of(L"\\");
		iniFile = path.substr(0, last);
		iniFile.append(L"\\inis");
		CreateDirectory(iniFile.c_str(), NULL);
		iniFile.append(L"\\USBqemu-wheel.ini");
	} else {
		iniFile.append(IniDir);
		iniFile.append(L"USBqemu-wheel.ini");
	}
}

void SaveConfig()
{
	Config *Conf1 = &conf;
	std::wstring szIniFile;
	TCHAR szValue[256];

	GetIniFile(szIniFile);

	FILE *f = nullptr;
	auto err = _wfopen_s(&f, szIniFile.c_str(), L"a+");
	if (!f) {
		MessageBoxW(NULL, L"Cannot save to ini!", L"USBqemu", MB_ICONERROR);
	} else
		fclose(f);

	swprintf_s(szValue,L"%u",Conf1->Log);
	WritePrivateProfileString(TEXT("Interface"), TEXT("Logging"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->DFPPass);
	WritePrivateProfileString(TEXT("Devices"), TEXT("DFP Passthrough"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->Port0);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Port 0"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->Port1);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Port 1"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->WheelType[0]);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 1"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->WheelType[1]);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 2"),szValue,szIniFile.c_str());

	WritePrivateProfileString(TEXT("Devices"), TEXT("USB Image"),Conf1->usb_img,szIniFile.c_str());

	WritePrivateProfileString(TEXT("Devices"), TEXT("Mic 1"), Conf1->mics[0].c_str(), szIniFile.c_str());
	WritePrivateProfileString(TEXT("Devices"), TEXT("Mic 2"), Conf1->mics[1].c_str(), szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->MicBuffering);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Mic Buffering"),szValue,szIniFile.c_str());

	//WritePrivateProfileString("Joystick", "Player1", player_joys[0].c_str(), szIniFile);
	//WritePrivateProfileString("Joystick", "Player2", player_joys[1].c_str(), szIniFile);

}

void LoadConfig() {

	Config *Conf1 = &conf;
	std::wstring szIniFile;
	TCHAR szValue[MAX_PATH+1];

	GetIniFile(szIniFile);

	FILE *fp = nullptr;
	auto err = _wfopen_s(&fp, szIniFile.c_str(), L"rt");//check if ini really exists
	if (fp)
	{
		memset(&conf, 0, sizeof(conf));
		conf.Log = 0;//default value
		SaveConfig();//save and return
		return ;
	}
	fclose(fp);

	GetPrivateProfileString(TEXT("Interface"), TEXT("Logging"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->Log = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("DFP Passthrough"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->DFPPass = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Port 0"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->Port0 = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Port 1"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->Port1 = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 1"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->WheelType[0] = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 2"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->WheelType[1] = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("USB Image"), NULL, Conf1->usb_img, sizeof(Conf1->usb_img), szIniFile.c_str());

	// Get mics
	TCHAR tmp[1024];
	GetPrivateProfileString(TEXT("Devices"), TEXT("Mic 1"), NULL, tmp, sizeof(tmp)/sizeof(*tmp), szIniFile.c_str());
	Conf1->mics[0] = tmp;

	GetPrivateProfileString(TEXT("Devices"), TEXT("Mic 2"), NULL, tmp, sizeof(tmp)/sizeof(*tmp), szIniFile.c_str());
	Conf1->mics[1] = tmp;

	GetPrivateProfileString(TEXT("Devices"), TEXT("Mic Buffering"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->MicBuffering = wcstoul(szValue, NULL, 10);
	if(Conf1->MicBuffering == 0)
		Conf1->MicBuffering = 50;

	//GetPrivateProfileString("Joystick", "Player1", NULL, szValue, MAX_PATH, szIniFile);
	//player_joys[0] = szValue;

	//GetPrivateProfileString("Joystick", "Player2", NULL, szValue, MAX_PATH, szIniFile);
	//player_joys[1] = szValue;

	return ;

}

<commit_msg>WIN32: Ugh, check if file handle IS null.<commit_after>#include <string>
#include <stdlib.h>

#include "../USB.h"

extern HINSTANCE hInst;
std::wstring IniDir;
std::wstring LogDir;

void CALLBACK USBsetSettingsDir( const char* dir )
{
	fprintf(stderr, "USBsetSettingsDir: %s\n", dir);
	wchar_t dst[4096] = {0};
	mbstowcs(dst, dir, ARRAYSIZE(dst));
	IniDir = dst;
}

void CALLBACK USBsetLogDir( const char* dir )
{
	printf("USBsetLogDir: %s\n", dir);
	wchar_t dst[4096] = {0};
	mbstowcs(dst, dir, ARRAYSIZE(dst));
	LogDir = dst;
}

void GetIniFile(std::wstring &iniFile)
{
	iniFile.clear();
	if(!IniDir.length()) {
		TCHAR tmp[MAX_PATH] = {0};
		GetModuleFileName(GetModuleHandle((LPWSTR)hInst), tmp, MAX_PATH);

		std::wstring path(tmp);
		unsigned last = path.find_last_of(L"\\");
		iniFile = path.substr(0, last);
		iniFile.append(L"\\inis");
		CreateDirectory(iniFile.c_str(), NULL);
		iniFile.append(L"\\USBqemu-wheel.ini");
	} else {
		iniFile.append(IniDir);
		iniFile.append(L"USBqemu-wheel.ini");
	}
}

void SaveConfig()
{
	Config *Conf1 = &conf;
	std::wstring szIniFile;
	TCHAR szValue[256];

	GetIniFile(szIniFile);

	FILE *f = nullptr;
	auto err = _wfopen_s(&f, szIniFile.c_str(), L"a+");
	if (!f) {
		MessageBoxW(NULL, L"Cannot save to ini!", L"USBqemu", MB_ICONERROR);
	} else
		fclose(f);

	swprintf_s(szValue,L"%u",Conf1->Log);
	WritePrivateProfileString(TEXT("Interface"), TEXT("Logging"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->DFPPass);
	WritePrivateProfileString(TEXT("Devices"), TEXT("DFP Passthrough"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->Port0);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Port 0"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->Port1);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Port 1"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->WheelType[0]);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 1"),szValue,szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->WheelType[1]);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 2"),szValue,szIniFile.c_str());

	WritePrivateProfileString(TEXT("Devices"), TEXT("USB Image"),Conf1->usb_img,szIniFile.c_str());

	WritePrivateProfileString(TEXT("Devices"), TEXT("Mic 1"), Conf1->mics[0].c_str(), szIniFile.c_str());
	WritePrivateProfileString(TEXT("Devices"), TEXT("Mic 2"), Conf1->mics[1].c_str(), szIniFile.c_str());

	swprintf_s(szValue,L"%u",Conf1->MicBuffering);
	WritePrivateProfileString(TEXT("Devices"), TEXT("Mic Buffering"),szValue,szIniFile.c_str());

	//WritePrivateProfileString("Joystick", "Player1", player_joys[0].c_str(), szIniFile);
	//WritePrivateProfileString("Joystick", "Player2", player_joys[1].c_str(), szIniFile);

}

void LoadConfig() {

	Config *Conf1 = &conf;
	std::wstring szIniFile;
	TCHAR szValue[MAX_PATH+1];

	GetIniFile(szIniFile);

	FILE *fp = nullptr;
	auto err = _wfopen_s(&fp, szIniFile.c_str(), L"rt");//check if ini really exists
	if (!fp)
	{
		memset(&conf, 0, sizeof(conf));
		conf.Log = 0;//default value
		SaveConfig();//save and return
		return ;
	}
	fclose(fp);

	GetPrivateProfileString(TEXT("Interface"), TEXT("Logging"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->Log = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("DFP Passthrough"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->DFPPass = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Port 0"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->Port0 = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Port 1"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->Port1 = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 1"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->WheelType[0] = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("Wheel Type 2"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->WheelType[1] = wcstoul(szValue, NULL, 10);

	GetPrivateProfileString(TEXT("Devices"), TEXT("USB Image"), NULL, Conf1->usb_img, sizeof(Conf1->usb_img), szIniFile.c_str());

	// Get mics
	TCHAR tmp[1024];
	GetPrivateProfileString(TEXT("Devices"), TEXT("Mic 1"), NULL, tmp, sizeof(tmp)/sizeof(*tmp), szIniFile.c_str());
	Conf1->mics[0] = tmp;

	GetPrivateProfileString(TEXT("Devices"), TEXT("Mic 2"), NULL, tmp, sizeof(tmp)/sizeof(*tmp), szIniFile.c_str());
	Conf1->mics[1] = tmp;

	GetPrivateProfileString(TEXT("Devices"), TEXT("Mic Buffering"), NULL, szValue, 20, szIniFile.c_str());
	Conf1->MicBuffering = wcstoul(szValue, NULL, 10);
	if(Conf1->MicBuffering == 0)
		Conf1->MicBuffering = 50;

	//GetPrivateProfileString("Joystick", "Player1", NULL, szValue, MAX_PATH, szIniFile);
	//player_joys[0] = szValue;

	//GetPrivateProfileString("Joystick", "Player2", NULL, szValue, MAX_PATH, szIniFile);
	//player_joys[1] = szValue;

	return ;

}

<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/net.hxx>
#include <abaclade/thread.hxx>

#if ABC_HOST_API_POSIX
   #include <arpa/inet.h> // inet_addr()
   #include <errno.h> // EINTR errno
   #include <sys/types.h> // sockaddr sockaddr_in
   #include <sys/socket.h> // accept4() bind() socket()
#elif ABC_HOST_API_WIN32
   #include <winsock2.h>
   #if ABC_HOST_CXX_MSC
      // Silence warnings from system header files.
      #pragma warning(push)

      // “'id' : conversion from 'type1' to 'type2', signed / unsigned mismatch”
      #pragma warning(disable: 4365)
   #endif
   #include <ws2tcpip.h>
   #include <mstcpip.h>
   #if ABC_HOST_CXX_MSC
      #pragma warning(pop)
   #endif
   #if _WIN32_WINNT == 0x0500
      // Additional header required for Windows 2000 IPv6 Tech Preview.
      #include <tpipv6.h>
   #endif
#endif

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

namespace abc { namespace net {

static detail::raw_ip_address const gc_abAny4 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4
};
static detail::raw_ip_address const gc_abAny6 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 6
};

ip_address const & ip_address::any_ipv4 = static_cast<ip_address const &>(gc_abAny4);
ip_address const & ip_address::any_ipv6 = static_cast<ip_address const &>(gc_abAny6);

}} //namespace abc::net

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

namespace abc { namespace net {

connection::connection(io::filedesc fd, ip_address && ipaddrRemote, port_t portRemote) :
   m_bfrw(io::binary::make_readwriter(std::move(fd))),
   m_ipaddrRemote(std::move(ipaddrRemote)),
   m_portRemote(portRemote) {
}

connection::~connection() {
}

}} //namespace abc::net

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

namespace abc { namespace net {

tcp_server::tcp_server(ip_address const & ipaddr, port_t port, unsigned cBacklog /*= 5*/) :
   m_fdSocket(create_socket(ipaddr.version())),
   m_iIPVersion(ipaddr.version()) {
   ABC_TRACE_FUNC(this/*, ipaddr*/, port, cBacklog);

#if ABC_HOST_API_POSIX
   typedef ::sockaddr sockaddr_type;
   typedef ::socklen_t socklen_type;
#elif ABC_HOST_API_WIN32
   typedef ::SOCKADDR sockaddr_type;
   typedef int socklen_type;
#else
   #error "TODO: HOST_API"
#endif
   sockaddr_type * psaServer;
   socklen_type cbServer;
   ::sockaddr_in saServer4;
   ::sockaddr_in6 saServer6;
   switch (m_iIPVersion) {
      case 4:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer4);
         cbServer = sizeof saServer4;
         memory::clear(&saServer4);
         saServer4.sin_family = AF_INET;
         memory::copy(
            reinterpret_cast<std::uint8_t *>(&saServer4.sin_addr.s_addr),
            ipaddr.raw(),
            sizeof(ip_address::ipv4_type)
         );
         saServer4.sin_addr.s_addr = htonl(saServer4.sin_addr.s_addr);
         saServer4.sin_port = htons(port);
         break;
      case 6:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer6);
         cbServer = sizeof saServer6;
         memory::clear(&saServer6);
         //saServer6.sin6_flowinfo = 0;
         saServer6.sin6_family = AF_INET6;
         memory::copy(saServer6.sin6_addr.s6_addr, ipaddr.raw(), sizeof(ip_address::ipv6_type));
         saServer6.sin6_port = htons(port);
         break;
      ABC_SWITCH_WITHOUT_DEFAULT
   }
#if ABC_HOST_API_WIN32
   if (::bind(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), psaServer, cbServer) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
   if (::listen(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
#else
   if (::bind(m_fdSocket.get(), psaServer, cbServer) < 0) {
      exception::throw_os_error();
   }
   if (::listen(m_fdSocket.get(), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error();
   }
#endif
}

tcp_server::~tcp_server() {
#if ABC_HOST_API_WIN32
   ::WSACleanup();
#endif
}

std::shared_ptr<connection> tcp_server::accept() {
   ABC_TRACE_FUNC(this);

#if ABC_HOST_API_POSIX
   typedef ::sockaddr sockaddr_type;
   typedef ::socklen_t socklen_type;
#elif ABC_HOST_API_WIN32
   typedef ::SOCKADDR sockaddr_type;
   typedef int socklen_type;
#else
   #error "TODO: HOST_API"
#endif
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   io::filedesc fd;
   sockaddr_type * psaClient;
   socklen_type cbClient;
   ::sockaddr_in saClient4;
   ::sockaddr_in6 saClient6;
   if (m_iIPVersion == 4) {
      psaClient = reinterpret_cast<sockaddr_type *>(&saClient4);
      cbClient = sizeof saClient4;
   } else {
      psaClient = reinterpret_cast<sockaddr_type *>(&saClient6);
      cbClient = sizeof saClient6;
   }
   for (;;) {
      socklen_type cb = cbClient;
#if ABC_HOST_API_DARWIN
      // accept4() is not available, so emulate it with accept() + fcntl().
      fd = io::filedesc(::accept(m_fdSocket.get(), psaClient, &cb));
      if (fd) {
         /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
         thread won’t leak the file descriptor. That’s the whole point of accept4(). */
         fd.set_close_on_exec(true);
         if (bAsync) {
            fd.set_nonblocking(true);
         }
      }
#elif ABC_HOST_API_POSIX
      int iFlags = SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make the client socket non-blocking.
         iFlags |= SOCK_NONBLOCK;
      }
      fd = io::filedesc(::accept4(m_fdSocket.get(), psaClient, &cb, iFlags));
#elif ABC_HOST_API_WIN32
      fd = io::filedesc(reinterpret_cast<io::filedesc_t>(::WSAAccept(
         reinterpret_cast< ::SOCKET>(m_fdSocket.get()), psaClient, &cb, nullptr, 0
      )));
#else
   #error "TODO: HOST_API"
#endif
      if (fd) {
         cbClient = cb;
         break;
      }
#if ABC_HOST_API_POSIX
      int iErr = errno;
      switch (iErr) {
         case EINTR:
            break;
         case EAGAIN:
   #if EWOULDBLOCK != EAGAIN
         case EWOULDBLOCK:
   #endif
#elif ABC_HOST_API_WIN32
      int iErr = ::WSAGetLastError();
      switch (iErr) {
         case WSAEWOULDBLOCK:
#else
   #error "TODO: HOST_API"
#endif
            // Wait for m_fdSocket. Accepting a connection is considered a read event.
            this_coroutine::sleep_until_fd_ready(m_fdSocket, false);
            break;
         default:
            exception::throw_os_error(static_cast<errint_t>(iErr));
      }
   }

   ip_address ipaddrClient;
   port_t portClient;
   // TODO: validate cbClient and set ipaddrClient/portClient using saClient4/6.sin_addr.
   ipaddrClient = ip_address(0);
   portClient = 0;
   return std::make_shared<connection>(std::move(fd), std::move(ipaddrClient), portClient);
}

/*static*/ io::filedesc tcp_server::create_socket(std::uint8_t iIPVersion) {
   ABC_TRACE_FUNC(iIPVersion);

   if (iIPVersion != 4 && iIPVersion != 6) {
      // TODO: provide more information in the exception.
      ABC_THROW(domain_error, ());
   }
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   int iFamily = (iIPVersion == 4 ? AF_INET : AF_INET6);
   int iType = SOCK_STREAM;
#if ABC_HOST_API_POSIX
   #if !ABC_HOST_API_DARWIN
      iType |= SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make this socket non-blocking.
         iType |= SOCK_NONBLOCK;
      }
   #endif
   io::filedesc fd(::socket(iFamily, iType, 0));
   if (!fd) {
      exception::throw_os_error();
   }
   #if ABC_HOST_API_DARWIN
      /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
      thread won’t leak the file descriptor. That’s the whole point of the extra SOCK_* flags. */
      fd.set_close_on_exec(true);
      if (bAsync) {
         fd.set_nonblocking(true);
      }
   #endif
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   static std::uint8_t const sc_iWSAMajorVersion = 2, sc_iWSAMinorVersion = 2;
   WSADATA wsad;
   if (int iRet = ::WSAStartup(MAKEWORD(sc_iWSAMajorVersion, sc_iWSAMinorVersion), &wsad)) {
      exception::throw_os_error(static_cast<errint_t>(iRet));
   }
   if (
      LOBYTE(wsad.wVersion) != sc_iWSAMajorVersion || HIBYTE(wsad.wVersion) != sc_iWSAMinorVersion
   ) {
      // The loaded WinSock implementation does not support the requested version.
      ::WSACleanup();
      // TODO: use a better exception class.
      ABC_THROW(generic_error, ());
   }

   ::DWORD iFlags = 0;
   if (bAsync) {
      iFlags |= WSA_FLAG_OVERLAPPED;
   }
   #ifdef WSA_FLAG_NO_HANDLE_INHERIT
      iFlags |= WSA_FLAG_NO_HANDLE_INHERIT;
   #endif
   io::filedesc fd(reinterpret_cast<io::filedesc_t>(::WSASocket(
      iFamily, iType, 0, nullptr, 0, iFlags
   )));
   if (!fd) {
      exception::throw_os_error();
   }
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
   return std::move(fd);
}

}} //namespace abc::net
<commit_msg>Add #include required by FreeBSD<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/net.hxx>
#include <abaclade/thread.hxx>

#if ABC_HOST_API_POSIX
   #include <arpa/inet.h> // inet_addr()
   #include <errno.h> // EINTR errno
   #include <sys/types.h> // sockaddr sockaddr_in
   #include <sys/socket.h> // accept4() bind() socket()
   #if ABC_HOST_API_FREEBSD
      #include <netinet/in.h>
   #endif
#elif ABC_HOST_API_WIN32
   #include <winsock2.h>
   #if ABC_HOST_CXX_MSC
      // Silence warnings from system header files.
      #pragma warning(push)

      // “'id' : conversion from 'type1' to 'type2', signed / unsigned mismatch”
      #pragma warning(disable: 4365)
   #endif
   #include <ws2tcpip.h>
   #include <mstcpip.h>
   #if ABC_HOST_CXX_MSC
      #pragma warning(pop)
   #endif
   #if _WIN32_WINNT == 0x0500
      // Additional header required for Windows 2000 IPv6 Tech Preview.
      #include <tpipv6.h>
   #endif
#endif

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

namespace abc { namespace net {

static detail::raw_ip_address const gc_abAny4 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4
};
static detail::raw_ip_address const gc_abAny6 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 6
};

ip_address const & ip_address::any_ipv4 = static_cast<ip_address const &>(gc_abAny4);
ip_address const & ip_address::any_ipv6 = static_cast<ip_address const &>(gc_abAny6);

}} //namespace abc::net

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

namespace abc { namespace net {

connection::connection(io::filedesc fd, ip_address && ipaddrRemote, port_t portRemote) :
   m_bfrw(io::binary::make_readwriter(std::move(fd))),
   m_ipaddrRemote(std::move(ipaddrRemote)),
   m_portRemote(portRemote) {
}

connection::~connection() {
}

}} //namespace abc::net

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

namespace abc { namespace net {

tcp_server::tcp_server(ip_address const & ipaddr, port_t port, unsigned cBacklog /*= 5*/) :
   m_fdSocket(create_socket(ipaddr.version())),
   m_iIPVersion(ipaddr.version()) {
   ABC_TRACE_FUNC(this/*, ipaddr*/, port, cBacklog);

#if ABC_HOST_API_POSIX
   typedef ::sockaddr sockaddr_type;
   typedef ::socklen_t socklen_type;
#elif ABC_HOST_API_WIN32
   typedef ::SOCKADDR sockaddr_type;
   typedef int socklen_type;
#else
   #error "TODO: HOST_API"
#endif
   sockaddr_type * psaServer;
   socklen_type cbServer;
   ::sockaddr_in saServer4;
   ::sockaddr_in6 saServer6;
   switch (m_iIPVersion) {
      case 4:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer4);
         cbServer = sizeof saServer4;
         memory::clear(&saServer4);
         saServer4.sin_family = AF_INET;
         memory::copy(
            reinterpret_cast<std::uint8_t *>(&saServer4.sin_addr.s_addr),
            ipaddr.raw(),
            sizeof(ip_address::ipv4_type)
         );
         saServer4.sin_addr.s_addr = htonl(saServer4.sin_addr.s_addr);
         saServer4.sin_port = htons(port);
         break;
      case 6:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer6);
         cbServer = sizeof saServer6;
         memory::clear(&saServer6);
         //saServer6.sin6_flowinfo = 0;
         saServer6.sin6_family = AF_INET6;
         memory::copy(saServer6.sin6_addr.s6_addr, ipaddr.raw(), sizeof(ip_address::ipv6_type));
         saServer6.sin6_port = htons(port);
         break;
      ABC_SWITCH_WITHOUT_DEFAULT
   }
#if ABC_HOST_API_WIN32
   if (::bind(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), psaServer, cbServer) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
   if (::listen(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
#else
   if (::bind(m_fdSocket.get(), psaServer, cbServer) < 0) {
      exception::throw_os_error();
   }
   if (::listen(m_fdSocket.get(), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error();
   }
#endif
}

tcp_server::~tcp_server() {
#if ABC_HOST_API_WIN32
   ::WSACleanup();
#endif
}

std::shared_ptr<connection> tcp_server::accept() {
   ABC_TRACE_FUNC(this);

#if ABC_HOST_API_POSIX
   typedef ::sockaddr sockaddr_type;
   typedef ::socklen_t socklen_type;
#elif ABC_HOST_API_WIN32
   typedef ::SOCKADDR sockaddr_type;
   typedef int socklen_type;
#else
   #error "TODO: HOST_API"
#endif
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   io::filedesc fd;
   sockaddr_type * psaClient;
   socklen_type cbClient;
   ::sockaddr_in saClient4;
   ::sockaddr_in6 saClient6;
   if (m_iIPVersion == 4) {
      psaClient = reinterpret_cast<sockaddr_type *>(&saClient4);
      cbClient = sizeof saClient4;
   } else {
      psaClient = reinterpret_cast<sockaddr_type *>(&saClient6);
      cbClient = sizeof saClient6;
   }
   for (;;) {
      socklen_type cb = cbClient;
#if ABC_HOST_API_DARWIN
      // accept4() is not available, so emulate it with accept() + fcntl().
      fd = io::filedesc(::accept(m_fdSocket.get(), psaClient, &cb));
      if (fd) {
         /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
         thread won’t leak the file descriptor. That’s the whole point of accept4(). */
         fd.set_close_on_exec(true);
         if (bAsync) {
            fd.set_nonblocking(true);
         }
      }
#elif ABC_HOST_API_POSIX
      int iFlags = SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make the client socket non-blocking.
         iFlags |= SOCK_NONBLOCK;
      }
      fd = io::filedesc(::accept4(m_fdSocket.get(), psaClient, &cb, iFlags));
#elif ABC_HOST_API_WIN32
      fd = io::filedesc(reinterpret_cast<io::filedesc_t>(::WSAAccept(
         reinterpret_cast< ::SOCKET>(m_fdSocket.get()), psaClient, &cb, nullptr, 0
      )));
#else
   #error "TODO: HOST_API"
#endif
      if (fd) {
         cbClient = cb;
         break;
      }
#if ABC_HOST_API_POSIX
      int iErr = errno;
      switch (iErr) {
         case EINTR:
            break;
         case EAGAIN:
   #if EWOULDBLOCK != EAGAIN
         case EWOULDBLOCK:
   #endif
#elif ABC_HOST_API_WIN32
      int iErr = ::WSAGetLastError();
      switch (iErr) {
         case WSAEWOULDBLOCK:
#else
   #error "TODO: HOST_API"
#endif
            // Wait for m_fdSocket. Accepting a connection is considered a read event.
            this_coroutine::sleep_until_fd_ready(m_fdSocket, false);
            break;
         default:
            exception::throw_os_error(static_cast<errint_t>(iErr));
      }
   }

   ip_address ipaddrClient;
   port_t portClient;
   // TODO: validate cbClient and set ipaddrClient/portClient using saClient4/6.sin_addr.
   ipaddrClient = ip_address(0);
   portClient = 0;
   return std::make_shared<connection>(std::move(fd), std::move(ipaddrClient), portClient);
}

/*static*/ io::filedesc tcp_server::create_socket(std::uint8_t iIPVersion) {
   ABC_TRACE_FUNC(iIPVersion);

   if (iIPVersion != 4 && iIPVersion != 6) {
      // TODO: provide more information in the exception.
      ABC_THROW(domain_error, ());
   }
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   int iFamily = (iIPVersion == 4 ? AF_INET : AF_INET6);
   int iType = SOCK_STREAM;
#if ABC_HOST_API_POSIX
   #if !ABC_HOST_API_DARWIN
      iType |= SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make this socket non-blocking.
         iType |= SOCK_NONBLOCK;
      }
   #endif
   io::filedesc fd(::socket(iFamily, iType, 0));
   if (!fd) {
      exception::throw_os_error();
   }
   #if ABC_HOST_API_DARWIN
      /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
      thread won’t leak the file descriptor. That’s the whole point of the extra SOCK_* flags. */
      fd.set_close_on_exec(true);
      if (bAsync) {
         fd.set_nonblocking(true);
      }
   #endif
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   static std::uint8_t const sc_iWSAMajorVersion = 2, sc_iWSAMinorVersion = 2;
   WSADATA wsad;
   if (int iRet = ::WSAStartup(MAKEWORD(sc_iWSAMajorVersion, sc_iWSAMinorVersion), &wsad)) {
      exception::throw_os_error(static_cast<errint_t>(iRet));
   }
   if (
      LOBYTE(wsad.wVersion) != sc_iWSAMajorVersion || HIBYTE(wsad.wVersion) != sc_iWSAMinorVersion
   ) {
      // The loaded WinSock implementation does not support the requested version.
      ::WSACleanup();
      // TODO: use a better exception class.
      ABC_THROW(generic_error, ());
   }

   ::DWORD iFlags = 0;
   if (bAsync) {
      iFlags |= WSA_FLAG_OVERLAPPED;
   }
   #ifdef WSA_FLAG_NO_HANDLE_INHERIT
      iFlags |= WSA_FLAG_NO_HANDLE_INHERIT;
   #endif
   io::filedesc fd(reinterpret_cast<io::filedesc_t>(::WSASocket(
      iFamily, iType, 0, nullptr, 0, iFlags
   )));
   if (!fd) {
      exception::throw_os_error();
   }
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
   return std::move(fd);
}

}} //namespace abc::net
<|endoftext|>