<commit_before>/*
 * Copyright (C) 2011 Josh A. Beam
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <unistd.h>
#include <poll.h>
#include "Server.h"
#include "Util.h"

using namespace std;

ServerConnection::ServerConnection(HttpConnection *connectionValue,
                                   ResponderContext *contextValue)
{
	connection = connectionValue;
	context = contextValue;
}

Server::Server(const Address &address, unsigned short port)
 : m_address(address), m_port(port)
{
	if(address.getType() == ADDRESS_TYPE_IPV4) {
		// create IPv4 socket
		m_fd = socket(AF_INET, SOCK_STREAM, 0);
		if(m_fd == -1)
			throw "socket() failed";

		int value = 1;
		setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));

		struct sockaddr_in sin;
		bzero(&sin, sizeof(sin));
		sin.sin_family = AF_INET;
		sin.sin_port = htons(port);
		memcpy(&sin.sin_addr, address.getAddress(), 4);
		socklen_t len = sizeof(sin);

		if(bind(m_fd, (struct sockaddr *)&sin, len) == -1) {
			close(m_fd);
			throw "bind() failed";
		}
	} else {
		// create IPv6 socket
		m_fd = socket(AF_INET6, SOCK_STREAM, 0);
		if(m_fd == -1)
			throw "socket() failed";

		int value = 1;
		setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));

		struct sockaddr_in6 sin;
		bzero(&sin, sizeof(sin));
		sin.sin6_family = AF_INET6;
		sin.sin6_port = htons(port);
		memcpy(&sin.sin6_addr, address.getAddress(), 16);
		socklen_t len = sizeof(sin);

		if(bind(m_fd, (struct sockaddr *)&sin, len) == -1) {
			close(m_fd);
			throw "bind() failed";
		}
	}

	if(listen(m_fd, 0) == -1) {
		close(m_fd);
		throw "listen() failed";
	}
}

Server::~Server()
{
	// close bound socket
	close(m_fd);

	// delete all responders
	for(unsigned int i = 0; i < m_responders.size(); ++i)
		delete m_responders[i];

	// delete all HttpConnections and ResponderContexts
	for(unsigned int i = 0; i < m_connections.size(); ++i) {
		if(m_connections[i].context != NULL)
			delete m_connections[i].context;
		if(m_connections[i].connection != NULL)
			delete m_connections[i].connection;
	}
}

const Address &
Server::getAddress() const
{
	return m_address;
}

unsigned short
Server::getPort() const
{
	return m_port;
}

void
Server::attachResponder(Responder *responder)
{
	m_responders.insert(m_responders.begin(), responder);
}

HttpConnection *
Server::acceptHttpConnection()
{
	int fd;
	uint8_t address[16];
	AddressType type;
	unsigned short port;

	if(m_address.getType() == ADDRESS_TYPE_IPV4) {
		// accept IPv4 connection
		struct sockaddr_in sin;
		bzero(&sin, sizeof(sin));
		socklen_t len = sizeof(sin);

		fd = accept(m_fd, (struct sockaddr *)&sin, &len);
		if(fd == -1)
			throw "accept() failed";

		memcpy(address, &sin.sin_addr, 4);
		type = ADDRESS_TYPE_IPV4;
		port = ntohs(sin.sin_port);
	} else {
		// accept IPv6 connection
		struct sockaddr_in6 sin;
		bzero(&sin, sizeof(sin));
		socklen_t len = sizeof(sin);

		fd = accept(m_fd, (struct sockaddr *)&sin, &len);
		if(fd == -1)
			throw "accept() failed";

		memcpy(address, &sin.sin6_addr, 4);
		type = ADDRESS_TYPE_IPV6;
		port = ntohs(sin.sin6_port);
	}

	return new HttpConnection(fd, Address(address, type), port);
}

void
Server::processRequest(ServerConnection *conn)
{
	// loop through responders and stop when
	// one matches the request
	for(unsigned int i = 0; i < m_responders.size(); ++i) {
		Responder *responder = m_responders[i];
		if(responder->matchesRequest(conn->connection->getRequest())) {
			// respond to the request
			conn->context = responder->respond(conn->connection);

			// if no ResponderContext was returned,
			// delete the connection
			if(conn->context == NULL) {
				delete conn->connection;
				conn->connection = NULL;
			}

			break;
		}
	}
}

void
Server::cycle()
{
	long currentTime = getMilliseconds();
	long sleepTime = 1000;

	// process connections
	for(unsigned int i = 0; i < m_connections.size(); ++i) {
		ServerConnection *sconn = &(m_connections[i]);
		HttpConnection *conn = sconn->connection;

		// remove null elements (representing connections that
		// were deleted) from the vector
		if(conn == NULL) {
			if(sconn->context != NULL)
				delete sconn->context;
			m_connections.erase(m_connections.begin() + (i--));
			continue;
		}

		// remove connections that haven't had any activity in
		// 10 seconds and haven't reached the responding state
		if(conn->getState() != HTTP_CONNECTION_STATE_SENDING_RESPONSE &&
		   conn->getMillisecondsSinceLastRead() > 10000) {
			delete conn;
			if(sconn->context != NULL)
				delete sconn->context;
			m_connections.erase(m_connections.begin() + (i--));
			continue;
		}

		if(sconn->context != NULL) {
			long wakeupTime = sconn->context->getWakeupTime();
			if(wakeupTime <= currentTime) {
				// continue the context's response; it may return
				// a pointer to itself, a pointer to a new context,
				// or null if it's done
				sconn->context = sconn->context->continueResponse(conn);
			} else {
				long timeDiff = wakeupTime - currentTime;
				if(timeDiff < sleepTime)
					sleepTime = timeDiff;
			}
		}
	}

	// create pollfd array
	nfds_t bsIndex = (nfds_t)m_connections.size();
	nfds_t nfds = bsIndex + 1;
	struct pollfd *fds = new struct pollfd[nfds];

	// add each connection to fds
	for(unsigned int i = 0; i < m_connections.size(); ++i) {
		unsigned int tmp = i + 1;
		fds[tmp].fd = m_connections[i].connection->getFileDescriptor();
		fds[tmp].events = POLLIN;
		fds[tmp].revents = 0;
	}

	// add the bound socket to fds
	fds[bsIndex].fd = m_fd;
	fds[bsIndex].events = POLLIN;
	fds[bsIndex].revents = 0;

	// poll bound socket and connection sockets
	if(poll(fds, nfds, sleepTime) > 0) {
		// handle connections to the bound socket
		if(fds[bsIndex].revents & POLLIN) {
			HttpConnection *conn = acceptHttpConnection();
			m_connections.push_back(ServerConnection(conn));
		}

		// read from connections
		for(unsigned int i = 0; i < m_connections.size(); ++i) {
			if((fds[i].revents & POLLIN) == 0)
				continue;

			// read from the connection
			HttpConnection *conn = m_connections[i].connection;
			conn->doRead();

			switch(conn->getState()) {
				default:
					break;
				case HTTP_CONNECTION_STATE_SENDING_RESPONSE:
					// full request received
					processRequest(&m_connections[i]);
					break;
				case HTTP_CONNECTION_STATE_DONE:
					// remote host closed the connection
					delete conn;
					m_connections[i].connection = NULL;
					break;
			}
		}
	}

	delete [] fds;
}
<commit_msg>Fixed off-by-one issue introduced in last commit.<commit_after>/*
 * Copyright (C) 2011 Josh A. Beam
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <unistd.h>
#include <poll.h>
#include "Server.h"
#include "Util.h"

using namespace std;

ServerConnection::ServerConnection(HttpConnection *connectionValue,
                                   ResponderContext *contextValue)
{
	connection = connectionValue;
	context = contextValue;
}

Server::Server(const Address &address, unsigned short port)
 : m_address(address), m_port(port)
{
	if(address.getType() == ADDRESS_TYPE_IPV4) {
		// create IPv4 socket
		m_fd = socket(AF_INET, SOCK_STREAM, 0);
		if(m_fd == -1)
			throw "socket() failed";

		int value = 1;
		setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));

		struct sockaddr_in sin;
		bzero(&sin, sizeof(sin));
		sin.sin_family = AF_INET;
		sin.sin_port = htons(port);
		memcpy(&sin.sin_addr, address.getAddress(), 4);
		socklen_t len = sizeof(sin);

		if(bind(m_fd, (struct sockaddr *)&sin, len) == -1) {
			close(m_fd);
			throw "bind() failed";
		}
	} else {
		// create IPv6 socket
		m_fd = socket(AF_INET6, SOCK_STREAM, 0);
		if(m_fd == -1)
			throw "socket() failed";

		int value = 1;
		setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));

		struct sockaddr_in6 sin;
		bzero(&sin, sizeof(sin));
		sin.sin6_family = AF_INET6;
		sin.sin6_port = htons(port);
		memcpy(&sin.sin6_addr, address.getAddress(), 16);
		socklen_t len = sizeof(sin);

		if(bind(m_fd, (struct sockaddr *)&sin, len) == -1) {
			close(m_fd);
			throw "bind() failed";
		}
	}

	if(listen(m_fd, 0) == -1) {
		close(m_fd);
		throw "listen() failed";
	}
}

Server::~Server()
{
	// close bound socket
	close(m_fd);

	// delete all responders
	for(unsigned int i = 0; i < m_responders.size(); ++i)
		delete m_responders[i];

	// delete all HttpConnections and ResponderContexts
	for(unsigned int i = 0; i < m_connections.size(); ++i) {
		if(m_connections[i].context != NULL)
			delete m_connections[i].context;
		if(m_connections[i].connection != NULL)
			delete m_connections[i].connection;
	}
}

const Address &
Server::getAddress() const
{
	return m_address;
}

unsigned short
Server::getPort() const
{
	return m_port;
}

void
Server::attachResponder(Responder *responder)
{
	m_responders.insert(m_responders.begin(), responder);
}

HttpConnection *
Server::acceptHttpConnection()
{
	int fd;
	uint8_t address[16];
	AddressType type;
	unsigned short port;

	if(m_address.getType() == ADDRESS_TYPE_IPV4) {
		// accept IPv4 connection
		struct sockaddr_in sin;
		bzero(&sin, sizeof(sin));
		socklen_t len = sizeof(sin);

		fd = accept(m_fd, (struct sockaddr *)&sin, &len);
		if(fd == -1)
			throw "accept() failed";

		memcpy(address, &sin.sin_addr, 4);
		type = ADDRESS_TYPE_IPV4;
		port = ntohs(sin.sin_port);
	} else {
		// accept IPv6 connection
		struct sockaddr_in6 sin;
		bzero(&sin, sizeof(sin));
		socklen_t len = sizeof(sin);

		fd = accept(m_fd, (struct sockaddr *)&sin, &len);
		if(fd == -1)
			throw "accept() failed";

		memcpy(address, &sin.sin6_addr, 4);
		type = ADDRESS_TYPE_IPV6;
		port = ntohs(sin.sin6_port);
	}

	return new HttpConnection(fd, Address(address, type), port);
}

void
Server::processRequest(ServerConnection *conn)
{
	// loop through responders and stop when
	// one matches the request
	for(unsigned int i = 0; i < m_responders.size(); ++i) {
		Responder *responder = m_responders[i];
		if(responder->matchesRequest(conn->connection->getRequest())) {
			// respond to the request
			conn->context = responder->respond(conn->connection);

			// if no ResponderContext was returned,
			// delete the connection
			if(conn->context == NULL) {
				delete conn->connection;
				conn->connection = NULL;
			}

			break;
		}
	}
}

void
Server::cycle()
{
	long currentTime = getMilliseconds();
	long sleepTime = 1000;

	// process connections
	for(unsigned int i = 0; i < m_connections.size(); ++i) {
		ServerConnection *sconn = &(m_connections[i]);
		HttpConnection *conn = sconn->connection;

		// remove null elements (representing connections that
		// were deleted) from the vector
		if(conn == NULL) {
			if(sconn->context != NULL)
				delete sconn->context;
			m_connections.erase(m_connections.begin() + (i--));
			continue;
		}

		// remove connections that haven't had any activity in
		// 10 seconds and haven't reached the responding state
		if(conn->getState() != HTTP_CONNECTION_STATE_SENDING_RESPONSE &&
		   conn->getMillisecondsSinceLastRead() > 10000) {
			delete conn;
			if(sconn->context != NULL)
				delete sconn->context;
			m_connections.erase(m_connections.begin() + (i--));
			continue;
		}

		if(sconn->context != NULL) {
			long wakeupTime = sconn->context->getWakeupTime();
			if(wakeupTime <= currentTime) {
				// continue the context's response; it may return
				// a pointer to itself, a pointer to a new context,
				// or null if it's done
				sconn->context = sconn->context->continueResponse(conn);
			} else {
				long timeDiff = wakeupTime - currentTime;
				if(timeDiff < sleepTime)
					sleepTime = timeDiff;
			}
		}
	}

	// create pollfd array
	nfds_t bsIndex = (nfds_t)m_connections.size();
	nfds_t nfds = bsIndex + 1;
	struct pollfd *fds = new struct pollfd[nfds];

	// add each connection to fds
	for(unsigned int i = 0; i < m_connections.size(); ++i) {
		fds[i].fd = m_connections[i].connection->getFileDescriptor();
		fds[i].events = POLLIN;
		fds[i].revents = 0;
	}

	// add the bound socket to fds
	fds[bsIndex].fd = m_fd;
	fds[bsIndex].events = POLLIN;
	fds[bsIndex].revents = 0;

	// poll bound socket and connection sockets
	if(poll(fds, nfds, sleepTime) > 0) {
		// handle connections to the bound socket
		if(fds[bsIndex].revents & POLLIN) {
			HttpConnection *conn = acceptHttpConnection();
			m_connections.push_back(ServerConnection(conn));
		}

		// read from connections
		for(unsigned int i = 0; i < m_connections.size(); ++i) {
			if((fds[i].revents & POLLIN) == 0)
				continue;

			// read from the connection
			HttpConnection *conn = m_connections[i].connection;
			conn->doRead();

			switch(conn->getState()) {
				default:
					break;
				case HTTP_CONNECTION_STATE_SENDING_RESPONSE:
					// full request received
					processRequest(&m_connections[i]);
					break;
				case HTTP_CONNECTION_STATE_DONE:
					// remote host closed the connection
					delete conn;
					m_connections[i].connection = NULL;
					break;
			}
		}
	}

	delete [] fds;
}
<|endoftext|>


<commit_before>#include <Shifty.h>

Shifty::Shifty() {
}

void Shifty::setBitCount(int bitCount) {
  this->bitCount = bitCount;
  this->byteCount = bitCount/8;
  for(int i = 0; i < this->byteCount; i++) {
    this->writeBuffer[i] = 0;
    this->dataModes[i] = 0;
    this->readBuffer[i] = 0;
  }
}

void Shifty::setPins(int dataPin, int clockPin, int latchPin, int readPin) {
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(readPin, INPUT);
  this->dataPin = dataPin;
  this->clockPin = clockPin;
  this->latchPin = latchPin;
  if(readPin != -1) {
    this->readPin = readPin;
  }
}

void Shifty::setPins(int dataPin, int clockPin, int latchPin) {
  setPins(dataPin, clockPin, latchPin, -1);
}

void Shifty::batchWriteBegin() {
  batchWriteMode = true;
}

void Shifty::writeBit(int bitnum, bool value) {
  if(batchWriteMode) {
    writeBitSoft(bitnum, value);
  } else {
    writeBitHard(bitnum, value);
  }
}

void Shifty::batchWriteEnd() {
  writeAllBits();
  batchWriteMode = false;
}

void Shifty::batchReadBegin() {
  batchReadMode = true;
  readAllBits();
}

bool Shifty::readBit(int bitnum) {
  if(batchReadMode) {
    readBitSoft(bitnum);
  } else {
    readBitHard(bitnum);
  }
}

void Shifty::batchReadEnd() {
  batchReadMode = false;
}

void Shifty::bitMode(int bitnum, bool mode) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;
  byte b = this->dataModes[bytenum];
  bitSet(b, offset);
  this->dataModes[bytenum] = b;
}

void Shifty::writeBitSoft(int bitnum, bool value) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;
  byte b = this->writeBuffer[bytenum];
  bitWrite(b, offset, value);
  this->writeBuffer[bytenum] = b;
}

void Shifty::writeBitHard(int bitnum, bool value) {
  writeBitSoft(bitnum, value);
  writeAllBits();
}

void Shifty::writeAllBits() {
  digitalWrite(latchPin, LOW);
  digitalWrite(clockPin, LOW);
  for(int i = 0; i < this->byteCount; i++) {
    shiftOut(dataPin, clockPin, MSBFIRST, this->writeBuffer[i]);
  }
  digitalWrite(latchPin, HIGH);
}

bool Shifty::readBitSoft(int bitnum) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;

  return bitRead(this->readBuffer[bytenum], offset);
}

bool Shifty::readBitHard(int bitnum) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;

  // To read the bit, set all output pins except the pin we are looking at to 0
  for(int i = 0; i < this->byteCount; i++) {
    byte mask = this->dataModes[i];
    byte outb = this->writeBuffer[i];
    for(int j = 0; j < 8; j++) {
      if(bitRead(mask, j)) {
        if(i == bytenum && j == bitnum) {
          bitSet(outb, j);
        } else {
          bitClear(outb, j);
        }
      }
    }
  }

  // Flush
  writeAllBits();

  // Get our data pin
  bool value = digitalRead(this->readPin);

  // Set the cached value
  byte cacheb = this->readBuffer[bytenum];
  bitWrite(cacheb, offset, value);
  this->readBuffer[bytenum] = cacheb;
}

void Shifty::readAllBits() {
  for(int i = 0; i < this->byteCount; i++) {
    byte mask = this->dataModes[i];
    byte outb = this->writeBuffer[i];
    byte inb = 0;
    for(int j = 0; j < 8; j++) {
      if(bitRead(mask, j)) {
        readBitHard(i * 8 + j);
      }
    }
  }
}
<commit_msg>Update Shifty.cpp<commit_after>#include <Shifty.h>

Shifty::Shifty() {
}

void Shifty::setBitCount(int bitCount) {
  this->bitCount = bitCount;
  this->byteCount = bitCount/8;
  for(int i = 0; i < this->byteCount; i++) {
    this->writeBuffer[i] = 0;
    this->dataModes[i] = 0;
    this->readBuffer[i] = 0;
  }
}

void Shifty::setPins(int dataPin, int clockPin, int latchPin, int readPin) {
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(readPin, INPUT);
  this->dataPin = dataPin;
  this->clockPin = clockPin;
  this->latchPin = latchPin;
  if(readPin != -1) {
    this->readPin = readPin;
  }
}

void Shifty::setPins(int dataPin, int clockPin, int latchPin) {
  setPins(dataPin, clockPin, latchPin, -1);
}

void Shifty::batchWriteBegin() {
  batchWriteMode = true;
}

void Shifty::writeBit(int bitnum, bool value) {
  if(batchWriteMode) {
    writeBitSoft(bitnum, value);
  } else {
    writeBitHard(bitnum, value);
  }
}

void Shifty::batchWriteEnd() {
  writeAllBits();
  batchWriteMode = false;
}

void Shifty::batchReadBegin() {
  batchReadMode = true;
  readAllBits();
}

bool Shifty::readBit(int bitnum) {
  if(batchReadMode) {
    readBitSoft(bitnum);
  } else {
    readBitHard(bitnum);
  }
}

void Shifty::batchReadEnd() {
  batchReadMode = false;
}

void Shifty::setBitMode(int bitnum, bool mode) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;
  byte b = this->dataModes[bytenum];
  bitSet(b, offset);
  this->dataModes[bytenum] = b;
}

bool Shifty::getBitMode(int bitnum){ //true == input
  int bytenum = bitnum / 8; // get working byte offset
  int offset = bitnum % 8;  // get working bit offset
  byte b = this->dataModes[bytenum]; //set b to working byte
  return bitRead(this->dataModes[bytenum], offset);
}

void Shifty::writeBitSoft(int bitnum, bool value) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;
  byte b = this->writeBuffer[bytenum];
  bitWrite(b, offset, value);
  this->writeBuffer[bytenum] = b;
}

void Shifty::writeBitHard(int bitnum, bool value) {
  writeBitSoft(bitnum, value);
  writeAllBits();
}

void Shifty::writeAllBits() {
  digitalWrite(latchPin, LOW);
  digitalWrite(clockPin, LOW);
  for(int i = 0; i < this->byteCount; i++) {
    shiftOut(dataPin, clockPin, MSBFIRST, this->writeBuffer[i]);
  }
  digitalWrite(latchPin, HIGH);
}

bool Shifty::readBitSoft(int bitnum) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;

  return bitRead(this->readBuffer[bytenum], offset);
}

bool Shifty::readBitHard(int bitnum) {
  int bytenum = bitnum / 8;
  int offset = bitnum % 8;

  // To read the bit, set all output pins except the pin we are looking at to 0
  for(int i = 0; i < this->byteCount; i++) {
    byte mask = this->dataModes[i];
    byte outb = this->writeBuffer[i];
    for(int j = 0; j < 8; j++) {
      if(bitRead(mask, j)) {
        if(i == bytenum && j == bitnum) {
          bitSet(outb, j);
        } else {
          bitClear(outb, j);
        }
      }
    }
  }

  // Flush
  writeAllBits();

  // Get our data pin
  bool value = digitalRead(this->readPin);

  // Set the cached value
  byte cacheb = this->readBuffer[bytenum];
  bitWrite(cacheb, offset, value);
  this->readBuffer[bytenum] = cacheb;
}

void Shifty::readAllBits() {
  for(int i = 0; i < this->byteCount; i++) {
    byte mask = this->dataModes[i];
    byte outb = this->writeBuffer[i];
    byte inb = 0;
    for(int j = 0; j < 8; j++) {
      if(bitRead(mask, j)) {
        readBitHard(i * 8 + j);
      }
    }
  }
}
<|endoftext|>


<commit_before>#pragma once
#include <tuple>
#include "common.hpp"

namespace spn {
	//! bool値による型の選択
	template <int N, class T, class F>
	struct SelectType {
		using type = F;
	};
	template <class T, class F>
	struct SelectType<1,T,F> {
		using type = T;
	};
	template <int N, template<class> class T, template<class> class F>
	struct SelectTypeT {
		template <class I>
		using type = F<I>;
	};
	template <template<class> class T, template<class> class F>
	struct SelectTypeT<1,T,F> {
		template <class I>
		using type = T<I>;
	};

	//! 型変換判定
	template <class T, class U>
	class Conversion {
		public:
			typedef char Small;
			class Big { char d[2]; };
			static Small Test(U);
			static Big Test(...);
			static T MakeT();

		public:
			enum { exists =
				sizeof(Test(MakeT())) == sizeof(Small),
				sameType = 0};
	};
	template <class T>
	class Conversion<T,T> {
		public:
			enum { exists=1, sameType=1 };
	};
	template <class T>
	class Conversion<void, T> {
		public:
			enum { exists=0, sameType=0 };
	};
	template <class T>
	class Conversion<T, void> {
		public:
			enum { exists=0, sameType=0 };
	};
	template <>
	class Conversion<void, void> {
		public:
			enum { exists=1, sameType=1 };
	};

	template <class T, class U>
	constexpr bool IsDerived() { return Conversion<const U*, const T*>::exists && !Conversion<const T*, const void*>::sameType; }

	//! 特定の型を取り出す
	template <int N, class... TS>
	struct TypeAt;
	template <int N, class T, class... TS>
	struct TypeAt<N, T, TS...> {
		typedef typename TypeAt<N-1, TS...>::type	type;
	};
	template <class T, class... TS>
	struct TypeAt<0,T,TS...> {
		typedef T type;
	};

	//! タイプリストが指定のs型を含んでいるか
	template <class T, int N, class... TS>
	struct TypeFind;
	template <class T, int N, class T0, class... TS>
	struct TypeFind<T,N,T0,TS...> {
		enum { result=TypeFind<T,N+1,TS...>::result };
	};
	template <class T, int N, class... TS>
	struct TypeFind<T,N,T,TS...> {
		enum { result=N };
	};
	template <class T, int N>
	struct TypeFind<T,N> {
		enum { result=-1 };
	};

	//! ビットフィールド用: 必要なビット数を計算
	template <class... TS>
	struct MaxBit {
		enum { result=0 };
	};
	template <class T, class... TS>
	struct MaxBit<T,TS...> {
		enum { result=TValue<T::offset+T::length, MaxBit<TS...>::result>::great };
	};
	//! タイプリストの変数を並べた時に消費するメモリ量を計算
	template <class... TS>
	struct TypeSum {
		enum { result=0 };
	};
	template <class T, class... TS>
	struct TypeSum<T, TS...> {
		enum { result=sizeof(T)+TypeSum<TS...>::result };
	};

	template <class... TS>
	struct CType {
		template <int N>
		struct At {
			static_assert(N<sizeof...(TS),"At: out of index");
			using type = typename TypeAt<N,TS...>::type;
		};
		template <bool flag, int N, class DEFAULT>
		struct __At {
			using type = DEFAULT;
		};
		template <int N, class DEFAULT>
		struct __At<true,N,DEFAULT> {
			using type = typename At<N>::type;
		};
		template <int N, class DEFAULT=void>
		struct _At {
			using type = typename __At<TValue<N,sizeof...(TS)>::lesser, N,DEFAULT>::type;
		};
		template <class... TS2>
		using ConcatAfter = CType<TS..., TS2...>;
		template <class... TS2>
		using ConcatBefore = CType<TS2..., TS...>;

		template <class T>
		struct _Find {
			enum { result= TypeFind<T,0,TS...>::result };
		};
		template <class T>
		struct Find : _Find<T> {
			static_assert(_Find<T>::result>=0, "Find: not found");
		};
		template <class T>
		struct Has : std::integral_constant<bool, _Find<T>::result>=0> {};
		using AsTuple = std::tuple<TS...>;
		template <class Dummy=void>
		struct Another {
			using result = CType<decltype(TS()())...>;
		};
		constexpr static int size = sizeof...(TS);
		// 型がimcompleteなケースを考えてテンプレートクラスとしてある
		template <class Dummy=void>
		struct Size {
			constexpr static int sum = TypeSum<TS...>::result,
								maxbit = MaxBit<TS...>::result;
		};
	};
}
<commit_msg>CType: 先頭からのオフセット計算<commit_after>#pragma once
#include <tuple>
#include "common.hpp"

namespace spn {
	//! bool値による型の選択
	template <int N, class T, class F>
	struct SelectType {
		using type = F;
	};
	template <class T, class F>
	struct SelectType<1,T,F> {
		using type = T;
	};
	template <int N, template<class> class T, template<class> class F>
	struct SelectTypeT {
		template <class I>
		using type = F<I>;
	};
	template <template<class> class T, template<class> class F>
	struct SelectTypeT<1,T,F> {
		template <class I>
		using type = T<I>;
	};

	//! 型変換判定
	template <class T, class U>
	class Conversion {
		public:
			typedef char Small;
			class Big { char d[2]; };
			static Small Test(U);
			static Big Test(...);
			static T MakeT();

		public:
			enum { exists =
				sizeof(Test(MakeT())) == sizeof(Small),
				sameType = 0};
	};
	template <class T>
	class Conversion<T,T> {
		public:
			enum { exists=1, sameType=1 };
	};
	template <class T>
	class Conversion<void, T> {
		public:
			enum { exists=0, sameType=0 };
	};
	template <class T>
	class Conversion<T, void> {
		public:
			enum { exists=0, sameType=0 };
	};
	template <>
	class Conversion<void, void> {
		public:
			enum { exists=1, sameType=1 };
	};

	template <class T, class U>
	constexpr bool IsDerived() { return Conversion<const U*, const T*>::exists && !Conversion<const T*, const void*>::sameType; }

	//! 特定の型を取り出す
	template <int N, class... TS>
	struct TypeAt;
	template <int N, class T, class... TS>
	struct TypeAt<N, T, TS...> {
		typedef typename TypeAt<N-1, TS...>::type	type;
	};
	template <class T, class... TS>
	struct TypeAt<0,T,TS...> {
		typedef T type;
	};

	//! タイプリストが指定のs型を含んでいるか
	template <class T, int N, class... TS>
	struct TypeFind;
	template <class T, int N, class T0, class... TS>
	struct TypeFind<T,N,T0,TS...> {
		enum { result=TypeFind<T,N+1,TS...>::result };
	};
	template <class T, int N, class... TS>
	struct TypeFind<T,N,T,TS...> {
		enum { result=N };
	};
	template <class T, int N>
	struct TypeFind<T,N> {
		enum { result=-1 };
	};

	//! ビットフィールド用: 必要なビット数を計算
	template <class... TS>
	struct MaxBit {
		enum { result=0 };
	};
	template <class T, class... TS>
	struct MaxBit<T,TS...> {
		enum { result=TValue<T::offset+T::length, MaxBit<TS...>::result>::great };
	};
	//! タイプリストの変数を並べた時に消費するメモリ量を計算
	template <class... TS>
	struct TypeSum {
		enum { result=0 };
	};
	template <class T, class... TS>
	struct TypeSum<T, TS...> {
		enum { result=sizeof(T)+TypeSum<TS...>::result };
	};
	//! インデックス指定による先頭からのサイズ累計
	template <int N, template <class> class Getter, class... Ts2>
	struct _SumN {
		constexpr static int result = 0; };
	template <int N, template <class> class Getter, class T0, class... Ts2>
	struct _SumN<N, Getter, T0, Ts2...> {
		constexpr static int result = Getter<T0>::get() * (N>0 ? 1 : 0) + _SumN<N-1, Getter, Ts2...>::result; };
	//! タイプ指定による先頭からのサイズ累計
	template <class T, template <class> class Getter, class... Ts2>
	struct _SumT;
	template <class T, template <class> class Getter, class T0, class... Ts2>
	struct _SumT<T, Getter, T0, Ts2...> {
		constexpr static int result = Getter<T0>::get() + _SumT<T, Getter, Ts2...>::result; };
	template <class T, template <class> class Getter, class... Ts2>
	struct _SumT<T, Getter, T, Ts2...> {
		constexpr static int result = 0; };
	//! 通常の型サイズ取得クラス
	template <class T>
	struct GetSize_Normal {
		static constexpr int get() { return sizeof(T); }
	};

	template <class... TS>
	struct CType {
		template <int N>
		struct At {
			static_assert(N<sizeof...(TS),"At: out of index");
			using type = typename TypeAt<N,TS...>::type;
		};
		template <bool flag, int N, class DEFAULT>
		struct __At {
			using type = DEFAULT;
		};
		template <int N, class DEFAULT>
		struct __At<true,N,DEFAULT> {
			using type = typename At<N>::type;
		};
		template <int N, class DEFAULT=void>
		struct _At {
			using type = typename __At<TValue<N,sizeof...(TS)>::lesser, N,DEFAULT>::type;
		};
		template <class... TS2>
		using ConcatAfter = CType<TS..., TS2...>;
		template <class... TS2>
		using ConcatBefore = CType<TS2..., TS...>;

		template <class T>
		struct _Find {
			enum { result= TypeFind<T,0,TS...>::result };
		};
		template <class T>
		struct Find : _Find<T> {
			static_assert(_Find<T>::result>=0, "Find: not found");
		};
		template <class T>
		struct Has : std::integral_constant<bool, _Find<T>::result>=0> {};
		using AsTuple = std::tuple<TS...>;
		template <class Dummy=void>
		struct Another {
			using result = CType<decltype(TS()())...>;
		};
		constexpr static int size = sizeof...(TS);
		// 型がimcompleteなケースを考えてテンプレートクラスとしてある
		template <class Dummy=void>
		struct Size {
			constexpr static int sum = TypeSum<TS...>::result,
								maxbit = MaxBit<TS...>::result;
		};
		template <int N, template <class> class Getter=GetSize_Normal>
		struct SumN {
			static_assert(N<sizeof...(TS),"Sum: out of index");
			constexpr static int result = _SumN<N, Getter, TS...>::result; };
		template <class T, template <class> class Getter=GetSize_Normal>
		struct SumT {
			constexpr static int result = _SumT<T, Getter, TS...>::result; };
	};
}
<|endoftext|>


<commit_before>#include <catch2/catch.hpp>

#include "libslic3r/Model.hpp"
#include "libslic3r/Format/3mf.hpp"
#include "libslic3r/Format/STL.hpp"

#include <boost/filesystem/operations.hpp>

using namespace Slic3r;

SCENARIO("Reading 3mf file", "[3mf]") {
    GIVEN("umlauts in the path of the file") {
        Model model;
        WHEN("3mf model is read") {
        	std::string path = std::string(TEST_DATA_DIR) + "/test_3mf/Geräte/Büchse.3mf";
        	DynamicPrintConfig config;
            bool ret = load_3mf(path.c_str(), &config, &model, false);
            THEN("load should succeed") {
                REQUIRE(ret);
            }
        }
    }
}

SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") {
    GIVEN("world vertices coordinates before save") {
        // load a model from stl file
        Model src_model;
        std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl";
        load_stl(src_file.c_str(), &src_model);
        src_model.add_default_instances();

        ModelObject* src_object = src_model.objects.front();

        // apply generic transformation to the 1st volume
        Geometry::Transformation src_volume_transform;
        src_volume_transform.set_offset({ 10.0, 20.0, 0.0 });
        src_volume_transform.set_rotation({ Geometry::deg2rad(25.0), Geometry::deg2rad(35.0), Geometry::deg2rad(45.0) });
        src_volume_transform.set_scaling_factor({ 1.1, 1.2, 1.3 });
        src_volume_transform.set_mirror({ -1.0, 1.0, -1.0 });
        src_object->volumes.front()->set_transformation(src_volume_transform);

        // apply generic transformation to the 1st instance
        Geometry::Transformation src_instance_transform;
        src_instance_transform.set_offset({ 5.0, 10.0, 0.0 });
        src_instance_transform.set_rotation({ Geometry::deg2rad(12.0), Geometry::deg2rad(13.0), Geometry::deg2rad(14.0) });
        src_instance_transform.set_scaling_factor({ 0.9, 0.8, 0.7 });
        src_instance_transform.set_mirror({ 1.0, -1.0, -1.0 });
        src_object->instances.front()->set_transformation(src_instance_transform);

        WHEN("model is saved+loaded to/from 3mf file") {
            // save the model to 3mf file
            std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.3mf";
            store_3mf(test_file.c_str(), &src_model, nullptr, false);

            // load back the model from the 3mf file
            Model dst_model;
            DynamicPrintConfig dst_config;
            load_3mf(test_file.c_str(), &dst_config, &dst_model, false);
            boost::filesystem::remove(test_file);

            // compare meshes
            TriangleMesh src_mesh = src_model.mesh();
            src_mesh.repair();

            TriangleMesh dst_mesh = dst_model.mesh();
            dst_mesh.repair();

            bool res = src_mesh.its.vertices.size() == dst_mesh.its.vertices.size();
            if (res) {
                for (size_t i = 0; i < dst_mesh.its.vertices.size(); ++i) {
                    res &= dst_mesh.its.vertices[i].isApprox(src_mesh.its.vertices[i]);
                }
            }
            THEN("world vertices coordinates after load match") {
                REQUIRE(res);
            }
        }
    }
}

SCENARIO("2D convex hull of sinking object", "[3mf]") {
    GIVEN("model") {
        // load a model
        Model model;
        std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl";
        load_stl(src_file.c_str(), &model);
        model.add_default_instances();

        WHEN("model is rotated, scaled and set as sinking") {
            ModelObject* object = model.objects.front();
            object->center_around_origin(false);

            // set instance's attitude so that it is rotated, scaled and sinking
            ModelInstance* instance = object->instances.front();
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            instance->set_rotation(X, -M_PI / 4.0);
//            instance->set_rotation(Y, -M_PI / 4.0);
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            instance->set_offset(Vec3d::Zero());
            instance->set_scaling_factor({ 2.0, 2.0, 2.0 });

            // calculate 2D convex hull
            Polygon hull_2d = object->convex_hull_2d(instance->get_transformation().get_matrix());

            // verify result
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            Points result = {
                { -91501496, -15914144 },
                { 91501496, -15914144 },
                { 91501496, 4243 },
                { 78229680, 4246883 },
                { 56898100, 4246883 },
                { -85501496, 4242641 },
                { -91501496, 4243 }
            };

//            Points result = {
//                { -4242641, -16299551 },
//                { -4241,    -19502998 },
//                { 66824768, -19502998 },
//                { 66824768, 19502998 },
//                { -4244,    19502998 },
//                { -4242640, -8537523 }
//            };
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            for (const Point& p : hull_2d.points) {
                std::cout << p.x() << ", " << p.y() << "\n";
            }

            bool res = hull_2d.points == result;

//            bool res = hull_2d.points.size() == result.size();
//            if (res) {
//                for (size_t i = 0; i < result.size(); ++i) {
//                    Vec3d hull_p(unscale<double>(hull_2d.points[i].x()), unscale<double>(hull_2d.points[i].y()), 0.0);
//                    Vec3d res_p(unscale<double>(result[i].x()), unscale<double>(result[i].y()), 0.0);
//                    res &= res_p.isApprox(hull_p);
//                }
//            }
//
//            // this does not work on RaspberryPi for float precision problem: the x of 1st vertex ending up being -4242640 instead of -4242641
////            bool res = hull_2d.points == result;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

            THEN("2D convex hull should match with reference") {
                REQUIRE(res);
            }
        }
    }
}

<commit_msg>Code cleanup<commit_after>#include <catch2/catch.hpp>

#include "libslic3r/Model.hpp"
#include "libslic3r/Format/3mf.hpp"
#include "libslic3r/Format/STL.hpp"

#include <boost/filesystem/operations.hpp>

using namespace Slic3r;

SCENARIO("Reading 3mf file", "[3mf]") {
    GIVEN("umlauts in the path of the file") {
        Model model;
        WHEN("3mf model is read") {
        	std::string path = std::string(TEST_DATA_DIR) + "/test_3mf/Geräte/Büchse.3mf";
        	DynamicPrintConfig config;
            bool ret = load_3mf(path.c_str(), &config, &model, false);
            THEN("load should succeed") {
                REQUIRE(ret);
            }
        }
    }
}

SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") {
    GIVEN("world vertices coordinates before save") {
        // load a model from stl file
        Model src_model;
        std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl";
        load_stl(src_file.c_str(), &src_model);
        src_model.add_default_instances();

        ModelObject* src_object = src_model.objects.front();

        // apply generic transformation to the 1st volume
        Geometry::Transformation src_volume_transform;
        src_volume_transform.set_offset({ 10.0, 20.0, 0.0 });
        src_volume_transform.set_rotation({ Geometry::deg2rad(25.0), Geometry::deg2rad(35.0), Geometry::deg2rad(45.0) });
        src_volume_transform.set_scaling_factor({ 1.1, 1.2, 1.3 });
        src_volume_transform.set_mirror({ -1.0, 1.0, -1.0 });
        src_object->volumes.front()->set_transformation(src_volume_transform);

        // apply generic transformation to the 1st instance
        Geometry::Transformation src_instance_transform;
        src_instance_transform.set_offset({ 5.0, 10.0, 0.0 });
        src_instance_transform.set_rotation({ Geometry::deg2rad(12.0), Geometry::deg2rad(13.0), Geometry::deg2rad(14.0) });
        src_instance_transform.set_scaling_factor({ 0.9, 0.8, 0.7 });
        src_instance_transform.set_mirror({ 1.0, -1.0, -1.0 });
        src_object->instances.front()->set_transformation(src_instance_transform);

        WHEN("model is saved+loaded to/from 3mf file") {
            // save the model to 3mf file
            std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.3mf";
            store_3mf(test_file.c_str(), &src_model, nullptr, false);

            // load back the model from the 3mf file
            Model dst_model;
            DynamicPrintConfig dst_config;
            load_3mf(test_file.c_str(), &dst_config, &dst_model, false);
            boost::filesystem::remove(test_file);

            // compare meshes
            TriangleMesh src_mesh = src_model.mesh();
            src_mesh.repair();

            TriangleMesh dst_mesh = dst_model.mesh();
            dst_mesh.repair();

            bool res = src_mesh.its.vertices.size() == dst_mesh.its.vertices.size();
            if (res) {
                for (size_t i = 0; i < dst_mesh.its.vertices.size(); ++i) {
                    res &= dst_mesh.its.vertices[i].isApprox(src_mesh.its.vertices[i]);
                }
            }
            THEN("world vertices coordinates after load match") {
                REQUIRE(res);
            }
        }
    }
}

SCENARIO("2D convex hull of sinking object", "[3mf]") {
    GIVEN("model") {
        // load a model
        Model model;
        std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl";
        load_stl(src_file.c_str(), &model);
        model.add_default_instances();

        WHEN("model is rotated, scaled and set as sinking") {
            ModelObject* object = model.objects.front();
            object->center_around_origin(false);

            // set instance's attitude so that it is rotated, scaled and sinking
            ModelInstance* instance = object->instances.front();
            instance->set_rotation(X, -M_PI / 4.0);
            instance->set_offset(Vec3d::Zero());
            instance->set_scaling_factor({ 2.0, 2.0, 2.0 });

            // calculate 2D convex hull
            Polygon hull_2d = object->convex_hull_2d(instance->get_transformation().get_matrix());

            // verify result
            Points result = {
                { -91501496, -15914144 },
                { 91501496, -15914144 },
                { 91501496, 4243 },
                { 78229680, 4246883 },
                { 56898100, 4246883 },
                { -85501496, 4242641 },
                { -91501496, 4243 }
            };

            bool res = hull_2d.points == result;

            THEN("2D convex hull should match with reference") {
                REQUIRE(res);
            }
        }
    }
}

<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "taskschedulerinternal.h"
#include "../math/math.h"
#include "../sys/sysinfo.h"
#include <algorithm>

namespace embree
{
  size_t TaskScheduler::g_numThreads = 0;
  __thread TaskScheduler* TaskScheduler::g_instance = nullptr;
  __thread TaskScheduler::Thread* TaskScheduler::thread_local_thread = nullptr;
  TaskScheduler::ThreadPool* TaskScheduler::threadPool = nullptr;

  template<typename Predicate, typename Body>
  __forceinline void TaskScheduler::steal_loop(Thread& thread, const Predicate& pred, const Body& body)
  {
    while (true)
    {
      /*! some rounds that yield */
      for (size_t i=0; i<32; i++)
      {
        /*! some spinning rounds */
        const size_t threadCount = thread.threadCount();
        for (size_t j=0; j<1024; j+=threadCount)
        {
          if (!pred()) return;
          if (thread.scheduler->steal_from_other_threads(thread)) {
            i=j=0;
            body();
          }
        }
        yield();
      }
    }
  }

  /*! run this task */
  __dllexport void TaskScheduler::Task::run (Thread& thread) // FIXME: avoid as many __dllexports as possible
  {
    /* try to run if not already stolen */
    if (try_switch_state(INITIALIZED,DONE))
    {
      Task* prevTask = thread.task;
      thread.task = this;
      try {
        if (thread.scheduler->cancellingException == nullptr)
          closure->execute();
      } catch (...) {
        if (thread.scheduler->cancellingException == nullptr)
          thread.scheduler->cancellingException = std::current_exception();
      }
      thread.task = prevTask;
      add_dependencies(-1);
    }

    /* steal until all dependencies have completed */
    steal_loop(thread,
               [&] () { return dependencies>0; },
               [&] () { while (thread.tasks.execute_local(thread,this)); });

    /* now signal our parent task that we are finished */
    if (parent)
      parent->add_dependencies(-1);
  }

  __dllexport bool TaskScheduler::TaskQueue::execute_local(Thread& thread, Task* parent)
  {
    /* stop if we run out of local tasks or reach the waiting task */
    if (right == 0 || &tasks[right-1] == parent)
      return false;

    /* execute task */
    size_t oldRight = right;
    tasks[right-1].run(thread);
    if (right != oldRight) {
      THROW_RUNTIME_ERROR("you have to wait for spawned subtasks");
    }

    /* pop task and closure from stack */
    right--;
    if (tasks[right].stackPtr != size_t(-1))
      stackPtr = tasks[right].stackPtr;

    /* also move left pointer */
    if (left >= right) left.store(right.load());

    return right != 0;
  }

  bool TaskScheduler::TaskQueue::steal(Thread& thread)
  {
    size_t l = left;
    if (l < right)
      l = left++;
    else
      return false;

    if (!tasks[l].try_steal(thread.tasks.tasks[thread.tasks.right]))
      return false;

    thread.tasks.right++;
    return true;
  }

  /* we steal from the left */
  size_t TaskScheduler::TaskQueue::getTaskSizeAtLeft()
  {
    if (left >= right) return 0;
    return tasks[left].N;
  }

  static MutexSys g_mutex;
  static BarrierSys g_barrier(2);

  void threadPoolFunction(std::pair<TaskScheduler::ThreadPool*,size_t>* pair)
  {
    TaskScheduler::ThreadPool* pool = pair->first;
    size_t threadIndex = pair->second;
    g_barrier.wait();
    pool->thread_loop(threadIndex);
  }

  TaskScheduler::ThreadPool::ThreadPool(bool set_affinity)
    : numThreads(0), numThreadsRunning(0), set_affinity(set_affinity), running(false) {}

  __dllexport void TaskScheduler::ThreadPool::startThreads()
  {
    if (running) return;
    setNumThreads(numThreads,true);
  }

  void TaskScheduler::ThreadPool::setNumThreads(size_t newNumThreads, bool startThreads)
  {
    Lock<MutexSys> lock(g_mutex);

    if (newNumThreads == 0)
      newNumThreads = getNumberOfLogicalThreads();

    numThreads = newNumThreads;
    if (!startThreads && !running) return;
    running = true;
    size_t numThreadsActive = numThreadsRunning;

    mutex.lock();
    numThreadsRunning = newNumThreads;
    mutex.unlock();
    condition.notify_all();

    /* start new threads */
    for (size_t t=numThreadsActive; t<numThreads; t++)
    {
      if (t == 0) continue;
      auto pair = std::make_pair(this,t);
      threads.push_back(createThread((thread_func)threadPoolFunction,&pair,4*1024*1024,set_affinity ? t : -1));
      g_barrier.wait();
    }

    /* stop some threads if we reduce the number of threads */
    for (ssize_t t=numThreadsActive-1; t>=ssize_t(numThreadsRunning); t--) {
      if (t == 0) continue;
      embree::join(threads.back());
      threads.pop_back();
    }
  }

  TaskScheduler::ThreadPool::~ThreadPool()
  {
    /* leave all taskschedulers */
    mutex.lock();
    numThreadsRunning = 0;
    mutex.unlock();
    condition.notify_all();

    /* wait for threads to terminate */
    for (size_t i=0; i<threads.size(); i++)
      embree::join(threads[i]);
  }

  __dllexport void TaskScheduler::ThreadPool::add(const Ref<TaskScheduler>& scheduler)
  {
    mutex.lock();
    schedulers.push_back(scheduler);
    mutex.unlock();
    condition.notify_all();
  }

  __dllexport void TaskScheduler::ThreadPool::remove(const Ref<TaskScheduler>& scheduler)
  {
    Lock<MutexSys> lock(mutex);
    for (std::list<Ref<TaskScheduler> >::iterator it = schedulers.begin(); it != schedulers.end(); it++) {
      if (scheduler == *it) {
        schedulers.erase(it);
        return;
      }
    }
  }

  void TaskScheduler::ThreadPool::thread_loop(size_t globalThreadIndex)
  {
    while (globalThreadIndex < numThreadsRunning)
    {
      Ref<TaskScheduler> scheduler = NULL;
      ssize_t threadIndex = -1;
      {
        Lock<MutexSys> lock(mutex);
        condition.wait(mutex, [&] () { return globalThreadIndex >= numThreadsRunning || !schedulers.empty(); });
        if (globalThreadIndex >= numThreadsRunning) break;
        scheduler = schedulers.front();
        threadIndex = scheduler->allocThreadIndex();
      }
      scheduler->thread_loop(threadIndex);
    }
  }

  TaskScheduler::TaskScheduler()
    : threadCounter(0), anyTasksRunning(0), hasRootTask(false)
  {
    threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the join mode the worker threads also join
    for (size_t i=0; i<threadLocal.size(); i++)
      threadLocal[i].store(nullptr);
  }

  TaskScheduler::~TaskScheduler()
  {
    assert(threadCounter == 0);
  }

  __dllexport size_t TaskScheduler::threadIndex()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread) return thread->threadIndex;
    else        return 0;
  }

  __dllexport size_t TaskScheduler::threadCount() {
    return threadPool->size();
  }

  __dllexport TaskScheduler* TaskScheduler::instance()
  {
    if (g_instance == NULL) {
      g_instance = new TaskScheduler;
      g_instance->refInc();
    }
    return g_instance;
  }

  void TaskScheduler::create(size_t numThreads, bool set_affinity)
  {
    if (!threadPool) threadPool = new TaskScheduler::ThreadPool(set_affinity);
    threadPool->setNumThreads(numThreads,false);
  }

  void TaskScheduler::destroy() {
    delete threadPool; threadPool = nullptr;
  }

  __dllexport ssize_t TaskScheduler::allocThreadIndex()
  {
    size_t threadIndex = threadCounter++;
    assert(threadIndex < threadLocal.size());
    return threadIndex;
  }

  void TaskScheduler::join()
  {
    mutex.lock();
    size_t threadIndex = allocThreadIndex();
    condition.wait(mutex, [&] () { return hasRootTask.load(); });
    mutex.unlock();
    std::exception_ptr except = thread_loop(threadIndex);
    if (except != nullptr) std::rethrow_exception(except);
  }

  void TaskScheduler::reset() {
    hasRootTask = false;
  }

  void TaskScheduler::wait_for_threads(size_t threadCount)
  {
    while (threadCounter < threadCount-1)
      __pause_cpu();
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::thread() {
    return thread_local_thread;
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::swapThread(Thread* thread)
  {
    Thread* old = thread_local_thread;
    thread_local_thread = thread;
    return old;
  }

  __dllexport bool TaskScheduler::wait()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread == nullptr) return true;
    while (thread->tasks.execute_local(*thread,thread->task)) {};
    return thread->scheduler->cancellingException == nullptr;
  }

  std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
  {
    /* allocate thread structure */
    std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
    Thread& thread = *mthread;
    threadLocal[threadIndex].store(&thread);
    Thread* oldThread = swapThread(&thread);

    /* main thread loop */
    while (anyTasksRunning)
    {
      steal_loop(thread,
                 [&] () { return anyTasksRunning > 0; },
                 [&] () {
                   anyTasksRunning++;
                   while (thread.tasks.execute_local(thread,nullptr));
                   anyTasksRunning--;
                 });
    }
    threadLocal[threadIndex].store(nullptr);
    swapThread(oldThread);

    /* remember exception to throw */
    std::exception_ptr except = nullptr;
    if (cancellingException != nullptr) except = cancellingException;

    /* wait for all threads to terminate */
    threadCounter--;
	size_t loopIndex = 1;
#define LOOP_YIELD_THRESHOLD 4096
	while (threadCounter > 0) {
		if ((loopIndex % LOOP_YIELD_THRESHOLD) == 0)
			yield();
		else
			_mm_pause();

	  loopIndex++;
	}
    return except;
  }

  bool TaskScheduler::steal_from_other_threads(Thread& thread)
  {
    const size_t threadIndex = thread.threadIndex;
    const size_t threadCount = this->threadCounter;

    for (size_t i=1; i<threadCount; i++)
    {
      __pause_cpu(32);
      size_t otherThreadIndex = threadIndex+i;
      if (otherThreadIndex >= threadCount) otherThreadIndex -= threadCount;

      Thread* othread = threadLocal[otherThreadIndex].load();
      if (!othread)
        continue;

      if (othread->tasks.steal(thread))
        return true;
    }

    return false;
  }

  __dllexport void TaskScheduler::startThreads() {
    threadPool->startThreads();
  }

  __dllexport void TaskScheduler::addScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->add(scheduler);
  }

  __dllexport void TaskScheduler::removeScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->remove(scheduler);
  }
}
<commit_msg>added spinning loop when terminating threads in internal tasking system<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "taskschedulerinternal.h"
#include "../math/math.h"
#include "../sys/sysinfo.h"
#include <algorithm>

namespace embree
{
  size_t TaskScheduler::g_numThreads = 0;
  __thread TaskScheduler* TaskScheduler::g_instance = nullptr;
  __thread TaskScheduler::Thread* TaskScheduler::thread_local_thread = nullptr;
  TaskScheduler::ThreadPool* TaskScheduler::threadPool = nullptr;

  template<typename Predicate, typename Body>
  __forceinline void TaskScheduler::steal_loop(Thread& thread, const Predicate& pred, const Body& body)
  {
    while (true)
    {
      /*! some rounds that yield */
      for (size_t i=0; i<32; i++)
      {
        /*! some spinning rounds */
        const size_t threadCount = thread.threadCount();
        for (size_t j=0; j<1024; j+=threadCount)
        {
          if (!pred()) return;
          if (thread.scheduler->steal_from_other_threads(thread)) {
            i=j=0;
            body();
          }
        }
        yield();
      }
    }
  }

  /*! run this task */
  __dllexport void TaskScheduler::Task::run (Thread& thread) // FIXME: avoid as many __dllexports as possible
  {
    /* try to run if not already stolen */
    if (try_switch_state(INITIALIZED,DONE))
    {
      Task* prevTask = thread.task;
      thread.task = this;
      try {
        if (thread.scheduler->cancellingException == nullptr)
          closure->execute();
      } catch (...) {
        if (thread.scheduler->cancellingException == nullptr)
          thread.scheduler->cancellingException = std::current_exception();
      }
      thread.task = prevTask;
      add_dependencies(-1);
    }

    /* steal until all dependencies have completed */
    steal_loop(thread,
               [&] () { return dependencies>0; },
               [&] () { while (thread.tasks.execute_local(thread,this)); });

    /* now signal our parent task that we are finished */
    if (parent)
      parent->add_dependencies(-1);
  }

  __dllexport bool TaskScheduler::TaskQueue::execute_local(Thread& thread, Task* parent)
  {
    /* stop if we run out of local tasks or reach the waiting task */
    if (right == 0 || &tasks[right-1] == parent)
      return false;

    /* execute task */
    size_t oldRight = right;
    tasks[right-1].run(thread);
    if (right != oldRight) {
      THROW_RUNTIME_ERROR("you have to wait for spawned subtasks");
    }

    /* pop task and closure from stack */
    right--;
    if (tasks[right].stackPtr != size_t(-1))
      stackPtr = tasks[right].stackPtr;

    /* also move left pointer */
    if (left >= right) left.store(right.load());

    return right != 0;
  }

  bool TaskScheduler::TaskQueue::steal(Thread& thread)
  {
    size_t l = left;
    if (l < right)
      l = left++;
    else
      return false;

    if (!tasks[l].try_steal(thread.tasks.tasks[thread.tasks.right]))
      return false;

    thread.tasks.right++;
    return true;
  }

  /* we steal from the left */
  size_t TaskScheduler::TaskQueue::getTaskSizeAtLeft()
  {
    if (left >= right) return 0;
    return tasks[left].N;
  }

  static MutexSys g_mutex;
  static BarrierSys g_barrier(2);

  void threadPoolFunction(std::pair<TaskScheduler::ThreadPool*,size_t>* pair)
  {
    TaskScheduler::ThreadPool* pool = pair->first;
    size_t threadIndex = pair->second;
    g_barrier.wait();
    pool->thread_loop(threadIndex);
  }

  TaskScheduler::ThreadPool::ThreadPool(bool set_affinity)
    : numThreads(0), numThreadsRunning(0), set_affinity(set_affinity), running(false) {}

  __dllexport void TaskScheduler::ThreadPool::startThreads()
  {
    if (running) return;
    setNumThreads(numThreads,true);
  }

  void TaskScheduler::ThreadPool::setNumThreads(size_t newNumThreads, bool startThreads)
  {
    Lock<MutexSys> lock(g_mutex);

    if (newNumThreads == 0)
      newNumThreads = getNumberOfLogicalThreads();

    numThreads = newNumThreads;
    if (!startThreads && !running) return;
    running = true;
    size_t numThreadsActive = numThreadsRunning;

    mutex.lock();
    numThreadsRunning = newNumThreads;
    mutex.unlock();
    condition.notify_all();

    /* start new threads */
    for (size_t t=numThreadsActive; t<numThreads; t++)
    {
      if (t == 0) continue;
      auto pair = std::make_pair(this,t);
      threads.push_back(createThread((thread_func)threadPoolFunction,&pair,4*1024*1024,set_affinity ? t : -1));
      g_barrier.wait();
    }

    /* stop some threads if we reduce the number of threads */
    for (ssize_t t=numThreadsActive-1; t>=ssize_t(numThreadsRunning); t--) {
      if (t == 0) continue;
      embree::join(threads.back());
      threads.pop_back();
    }
  }

  TaskScheduler::ThreadPool::~ThreadPool()
  {
    /* leave all taskschedulers */
    mutex.lock();
    numThreadsRunning = 0;
    mutex.unlock();
    condition.notify_all();

    /* wait for threads to terminate */
    for (size_t i=0; i<threads.size(); i++)
      embree::join(threads[i]);
  }

  __dllexport void TaskScheduler::ThreadPool::add(const Ref<TaskScheduler>& scheduler)
  {
    mutex.lock();
    schedulers.push_back(scheduler);
    mutex.unlock();
    condition.notify_all();
  }

  __dllexport void TaskScheduler::ThreadPool::remove(const Ref<TaskScheduler>& scheduler)
  {
    Lock<MutexSys> lock(mutex);
    for (std::list<Ref<TaskScheduler> >::iterator it = schedulers.begin(); it != schedulers.end(); it++) {
      if (scheduler == *it) {
        schedulers.erase(it);
        return;
      }
    }
  }

  void TaskScheduler::ThreadPool::thread_loop(size_t globalThreadIndex)
  {
    while (globalThreadIndex < numThreadsRunning)
    {
      Ref<TaskScheduler> scheduler = NULL;
      ssize_t threadIndex = -1;
      {
        Lock<MutexSys> lock(mutex);
        condition.wait(mutex, [&] () { return globalThreadIndex >= numThreadsRunning || !schedulers.empty(); });
        if (globalThreadIndex >= numThreadsRunning) break;
        scheduler = schedulers.front();
        threadIndex = scheduler->allocThreadIndex();
      }
      scheduler->thread_loop(threadIndex);
    }
  }

  TaskScheduler::TaskScheduler()
    : threadCounter(0), anyTasksRunning(0), hasRootTask(false)
  {
    threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the join mode the worker threads also join
    for (size_t i=0; i<threadLocal.size(); i++)
      threadLocal[i].store(nullptr);
  }

  TaskScheduler::~TaskScheduler()
  {
    assert(threadCounter == 0);
  }

  __dllexport size_t TaskScheduler::threadIndex()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread) return thread->threadIndex;
    else        return 0;
  }

  __dllexport size_t TaskScheduler::threadCount() {
    return threadPool->size();
  }

  __dllexport TaskScheduler* TaskScheduler::instance()
  {
    if (g_instance == NULL) {
      g_instance = new TaskScheduler;
      g_instance->refInc();
    }
    return g_instance;
  }

  void TaskScheduler::create(size_t numThreads, bool set_affinity)
  {
    if (!threadPool) threadPool = new TaskScheduler::ThreadPool(set_affinity);
    threadPool->setNumThreads(numThreads,false);
  }

  void TaskScheduler::destroy() {
    delete threadPool; threadPool = nullptr;
  }

  __dllexport ssize_t TaskScheduler::allocThreadIndex()
  {
    size_t threadIndex = threadCounter++;
    assert(threadIndex < threadLocal.size());
    return threadIndex;
  }

  void TaskScheduler::join()
  {
    mutex.lock();
    size_t threadIndex = allocThreadIndex();
    condition.wait(mutex, [&] () { return hasRootTask.load(); });
    mutex.unlock();
    std::exception_ptr except = thread_loop(threadIndex);
    if (except != nullptr) std::rethrow_exception(except);
  }

  void TaskScheduler::reset() {
    hasRootTask = false;
  }

  void TaskScheduler::wait_for_threads(size_t threadCount)
  {
    while (threadCounter < threadCount-1)
      __pause_cpu();
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::thread() {
    return thread_local_thread;
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::swapThread(Thread* thread)
  {
    Thread* old = thread_local_thread;
    thread_local_thread = thread;
    return old;
  }

  __dllexport bool TaskScheduler::wait()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread == nullptr) return true;
    while (thread->tasks.execute_local(*thread,thread->task)) {};
    return thread->scheduler->cancellingException == nullptr;
  }

  std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
  {
    /* allocate thread structure */
    std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
    Thread& thread = *mthread;
    threadLocal[threadIndex].store(&thread);
    Thread* oldThread = swapThread(&thread);

    /* main thread loop */
    while (anyTasksRunning)
    {
      steal_loop(thread,
                 [&] () { return anyTasksRunning > 0; },
                 [&] () {
                   anyTasksRunning++;
                   while (thread.tasks.execute_local(thread,nullptr));
                   anyTasksRunning--;
                 });
    }
    threadLocal[threadIndex].store(nullptr);
    swapThread(oldThread);

    /* remember exception to throw */
    std::exception_ptr except = nullptr;
    if (cancellingException != nullptr) except = cancellingException;

    /* wait for all threads to terminate */
    threadCounter--;
#if defined(__WIN32__)
	size_t loopIndex = 1;
#endif
#define LOOP_YIELD_THRESHOLD 4096
	while (threadCounter > 0) {
#if defined(__WIN32__)
		if ((loopIndex % LOOP_YIELD_THRESHOLD) == 0)
			yield();
		else
			_mm_pause();
#endif
	  loopIndex++;
	}
    return except;
  }

  bool TaskScheduler::steal_from_other_threads(Thread& thread)
  {
    const size_t threadIndex = thread.threadIndex;
    const size_t threadCount = this->threadCounter;

    for (size_t i=1; i<threadCount; i++)
    {
      __pause_cpu(32);
      size_t otherThreadIndex = threadIndex+i;
      if (otherThreadIndex >= threadCount) otherThreadIndex -= threadCount;

      Thread* othread = threadLocal[otherThreadIndex].load();
      if (!othread)
        continue;

      if (othread->tasks.steal(thread))
        return true;
    }

    return false;
  }

  __dllexport void TaskScheduler::startThreads() {
    threadPool->startThreads();
  }

  __dllexport void TaskScheduler::addScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->add(scheduler);
  }

  __dllexport void TaskScheduler::removeScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->remove(scheduler);
  }
}
<|endoftext|>


<commit_before>#include "Wallet.hpp"

namespace Ethereum{namespace Connector{

Wallet::Wallet(Provider &provider) :
    _provider(provider)
{}

Collection<std::string> Wallet::getAccounts()
{
    return Collection<std::string>(_provider.request("eth_accounts"));
}

std::string Wallet::getCoinBase()
{
    Json::Value result = _provider.request("eth_coinbase");
    return result.asString();
}

BigInt Wallet::getBalance(const char *account, const char *type)
{
    Json::Value result = _provider.request("eth_getBalance", Arguments(account, type));
    return unhex<BigInt>(result.asCString());
}

BigInt Wallet::getBalance(const char *account)
{
    return getBalance(account, "latest");
}

BigInt Wallet::getBalance(const std::string &account)
{
    return getBalance(account.c_str());
}

BigInt Wallet::getPendingBalance(const char *account)
{
    return getBalance(account, "pending");
}

BigInt Wallet::getPendingBalance(const std::string &account)
{
    return getPendingBalance(account.c_str());
}

bool Wallet::unlockAccount(const char *address, const char *password, time_t time)
{
    Json::Value result = _provider.request("personal_unlockAccount", Arguments(address, password, (size_t)time));
    return result.asBool();
}

bool Wallet::unlockAccount(const std::string &address, const std::string &password, time_t time)
{
    return unlockAccount(address.c_str(), password.c_str(), time);
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, size_t nonce)
{

    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, gasPrice, gas, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, gas, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const char *data, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, data, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const char *data, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, data, gasPrice, gas, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const char *data, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, data, gas, nonce));
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, gasPrice, gas, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, gas, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const std::string &data, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, data.c_str());
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const std::string &data, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, data.c_str(), gasPrice, gas, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const std::string &data, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, data.c_str(), gas, nonce);
}

std::string Wallet::sendRawTransaction(const char *transaction)
{
    Json::Value result = _provider.request("eth_sendRawTransaction", Arguments(transaction));
    return result.asString();
}

std::string Wallet::sendRawTransaction(const std::string &transaction)
{
    return sendRawTransaction(transaction.c_str());
}

std::string Wallet::sign(const char *account, const char *data)
{
    Json::Value result = _provider.request("eth_sign", Arguments(account, data));
    return result.asString();
}

std::string Wallet::sign(const std::string &account, const std::string &data)
{
    return sign(account.c_str(), data.c_str());
}

inline std::string Wallet::sendTransactionRequest(const char *type, const Json::Value &params)
{
    Json::Value result = _provider.request(type, params);
    return result.asString();
}

}}
<commit_msg>return false on rpc error<commit_after>#include "Wallet.hpp"

namespace Ethereum{namespace Connector{

Wallet::Wallet(Provider &provider) :
    _provider(provider)
{}

Collection<std::string> Wallet::getAccounts()
{
    return Collection<std::string>(_provider.request("eth_accounts"));
}

std::string Wallet::getCoinBase()
{
    Json::Value result = _provider.request("eth_coinbase");
    return result.asString();
}

BigInt Wallet::getBalance(const char *account, const char *type)
{
    Json::Value result = _provider.request("eth_getBalance", Arguments(account, type));
    return unhex<BigInt>(result.asCString());
}

BigInt Wallet::getBalance(const char *account)
{
    return getBalance(account, "latest");
}

BigInt Wallet::getBalance(const std::string &account)
{
    return getBalance(account.c_str());
}

BigInt Wallet::getPendingBalance(const char *account)
{
    return getBalance(account, "pending");
}

BigInt Wallet::getPendingBalance(const std::string &account)
{
    return getPendingBalance(account.c_str());
}

bool Wallet::unlockAccount(const char *address, const char *password, time_t time)
{
    try
    {
        Json::Value result = _provider.request("personal_unlockAccount", Arguments(address, password, (size_t)time));
        return result.asBool();
    }
    catch(...)
    {}
    return false;
}

bool Wallet::unlockAccount(const std::string &address, const std::string &password, time_t time)
{
    return unlockAccount(address.c_str(), password.c_str(), time);
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, size_t nonce)
{

    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, gasPrice, gas, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, gas, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const char *data, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, data, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const char *data, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, data, gasPrice, gas, nonce));
}

std::string Wallet::sendTransaction(const char *from, const char *to, const BigInt &amount, const char *data, const BigInt &gas, size_t nonce)
{
    return sendTransactionRequest("eth_sendTransaction", TransactionParamsFactory::makeParams(from, to, amount, data, gas, nonce));
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, gasPrice, gas, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, gas, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const std::string &data, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, data.c_str());
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const std::string &data, const BigInt &gasPrice, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, data.c_str(), gasPrice, gas, nonce);
}

std::string Wallet::sendTransaction(const std::string &from, const std::string &to, const BigInt &amount, const std::string &data, const BigInt &gas, size_t nonce)
{
    return sendTransaction(from.c_str(), to.c_str(), amount, data.c_str(), gas, nonce);
}

std::string Wallet::sendRawTransaction(const char *transaction)
{
    Json::Value result = _provider.request("eth_sendRawTransaction", Arguments(transaction));
    return result.asString();
}

std::string Wallet::sendRawTransaction(const std::string &transaction)
{
    return sendRawTransaction(transaction.c_str());
}

std::string Wallet::sign(const char *account, const char *data)
{
    Json::Value result = _provider.request("eth_sign", Arguments(account, data));
    return result.asString();
}

std::string Wallet::sign(const std::string &account, const std::string &data)
{
    return sign(account.c_str(), data.c_str());
}

inline std::string Wallet::sendTransactionRequest(const char *type, const Json::Value &params)
{
    Json::Value result = _provider.request(type, params);
    return result.asString();
}

}}
<|endoftext|>


<commit_before>#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

#include "Tools/Exception/exception.hpp"

#include "Frozenbits_generator_file.hpp"

using namespace aff3ct::tools;

Frozenbits_generator_file
::Frozenbits_generator_file(const int K, const int N, const std::string& filename)
: Frozenbits_generator(K, N, 0.f), filename(filename)
{
}

Frozenbits_generator_file
::Frozenbits_generator_file(const int K, const int N, const float sigma)
: Frozenbits_generator(K, N, sigma), filename("")
{
}

void Frozenbits_generator_file
::evaluate()
{
	if(!load_channels_file(filename))
		throw invalid_argument(__FILE__, __LINE__, __func__, "'" + filename + "' file does not exist.");
}

bool Frozenbits_generator_file
::load_channels_file(const std::string& filename)
{
	std::ifstream in_code(filename.c_str());

	if (in_code.is_open())
	{
		std::string trash;
		in_code >> trash; // N

		try
		{
			if (std::stoi(trash) != this->N)
			{
				std::stringstream message;
				message << "'trash' has to be equal to 'N' ('trash' = " << trash << ", 'N' = " << this->N << ").";
				throw runtime_error(__FILE__, __LINE__, __func__, message.str());
			}
		}
		catch(std::exception&)
		{
			return false;
		}

		in_code >> trash; // type
		in_code >> trash; // sigma

		for (unsigned i = 0; i < this->best_channels.size(); i++)
			in_code >> this->best_channels[i];

		in_code.close();
		return true;
	}
	else
		return false;
}
<commit_msg>Fix errors management in frozen bit generator from file.<commit_after>#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

#include "Tools/Exception/exception.hpp"

#include "Frozenbits_generator_file.hpp"

using namespace aff3ct::tools;

Frozenbits_generator_file
::Frozenbits_generator_file(const int K, const int N, const std::string& filename)
: Frozenbits_generator(K, N, 0.f), filename(filename)
{
}

Frozenbits_generator_file
::Frozenbits_generator_file(const int K, const int N, const float sigma)
: Frozenbits_generator(K, N, sigma), filename("")
{
}

void Frozenbits_generator_file
::evaluate()
{
	if(!load_channels_file(filename))
		throw invalid_argument(__FILE__, __LINE__, __func__, "'" + filename + "' file does not exist.");
}

bool Frozenbits_generator_file
::load_channels_file(const std::string& filename)
{
	std::ifstream in_code(filename.c_str());

	if (in_code.is_open())
	{
		std::string trash;
		in_code >> trash; // N

		try
		{
			std::stoi(trash);
		}
		catch(std::exception&)
		{
			std::stringstream message;
			message << "'std::stoi' did not work, something went wrong when reading the file.";
			throw runtime_error(__FILE__, __LINE__, __func__, message.str());
		}

		if (std::stoi(trash) != this->N)
		{
			std::stringstream message;
			message << "'trash' has to be equal to 'N' ('trash' = " << trash << ", 'N' = " << this->N << ").";
			throw runtime_error(__FILE__, __LINE__, __func__, message.str());
		}

		in_code >> trash; // type
		in_code >> trash; // sigma

		for (unsigned i = 0; i < this->best_channels.size(); i++)
			in_code >> this->best_channels[i];

		in_code.close();
		return true;
	}
	else
		return false;
}
<|endoftext|>


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

#include <stdio.h>

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _OSL_SECURITY_HXX_
#include <osl/security.hxx>
#endif
#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif
#ifndef _VOS_PROCESS_HXX_
#include <vos/process.hxx>
#endif
#ifndef _RTL_TEXTENC_H
#include <rtl/textenc.h>
#endif
#ifndef _RTL_URI_H_
#include <rtl/uri.h>
#endif
#ifndef _RTL_URI_HXX_
#include <rtl/uri.hxx>
#endif

using namespace vos;
using namespace osl;
using namespace rtl;

#define PATH_DELEMITTER '/'

#define USER_REGISTRY_NAME_ENV      "STAR_USER_REGISTRY"
#define SYSTEM_REGISTRY_NAME_ENV    "STAR_REGISTRY"
#define REGISTRY_SYSTEM_NAME    "services.rdb"

#define REGISTRY_LOCAL_NAME     "user60.rdb"

#ifdef SAL_UNX
#define CONFIG_PATH_PREFIX      "."
#else
#define CONFIG_PATH_PREFIX      ""
#endif

namespace comphelper
{

/**
   @return sal_True, if the office is started in a portal
                     environment.
           sal_False, if the common office is started
 */
static sal_Bool retrievePortalUserDir( OUString *pDirectory )
{
    OStartupInfo startInfo;
    sal_uInt32 nArgs = startInfo.getCommandArgCount();
    sal_Bool bIsPortalUser = sal_False;
    OUString sArg;
    while( nArgs > 0 )
      {
        if ( !startInfo.getCommandArg(--nArgs, sArg) )
          {
            if ( sArg.indexOf(OUString::createFromAscii("-userid")) == 0 )
            {

                  bIsPortalUser = sal_True;
                sal_Int32 nStart = sArg.lastIndexOf( '[' );
                sal_Int32 nEnd   = sArg.lastIndexOf( ']' );
                if( -1 == nStart || -1 == nEnd || nEnd < nStart)
                {
                    *pDirectory = OUString();
                }
                else
                {
                    OUString aEncHome = sArg.copy( nStart + 1 , nEnd - nStart -1 );
                    *pDirectory = rtl::Uri::decode(aEncHome,
                                                   rtl_UriDecodeWithCharset,
                                                   RTL_TEXTENCODING_UTF8);
                }
                  break;
            }
          }
     }
    return bIsPortalUser;
}

static OUString getDefaultLocalRegistry()
{
    OUString uBuffer, userRegistryName;
    OUString portalUserDir;

    sal_Bool bIsPortalUser = retrievePortalUserDir( &portalUserDir );

    if ( bIsPortalUser )
       {
        if(  portalUserDir.getLength() )
        {
            FileBase::getFileURLFromSystemPath( portalUserDir , portalUserDir );
            userRegistryName = portalUserDir;
            userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
                "/user/" REGISTRY_LOCAL_NAME ) );

            // Directory creation is probably necessary for bootstrapping a new
            // user in the portal environment (the ucb uses this function).
            // This should be solved differently, as
            // no one expects this function to create anything ...
            OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
            OUString sPath(RTL_CONSTASCII_USTRINGPARAM("file://"));
            FileBase::RC retRC = FileBase::E_None;

            sal_Int32 nIndex = 3;
            sPath += userRegistryName.getToken(2, '/', nIndex);
            while( nIndex != -1 )
            {
                sPath += sSeparator;
                sPath += userRegistryName.getToken(0, '/', nIndex);
                if( nIndex == -1 )
                    break;
                Directory aDir( sPath );
                if( aDir.open() == FileBase::E_NOENT )
                {
                    retRC = Directory::create(sPath);
                    if ( retRC != FileBase::E_None && retRC != FileBase::E_EXIST)
                    {
                        return OUString();
                    }
                }
            }
        }
    }
    else /* bIsPortalUser */
    {
        ::osl::Security aUserSecurity;
        aUserSecurity.getConfigDir( userRegistryName );
        userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
            "/" CONFIG_PATH_PREFIX REGISTRY_LOCAL_NAME ) );
    }

    return userRegistryName;
}

OUString getPathToUserRegistry()
{
    OUString    userRegistryName;
    FILE        *f=NULL;

    // search the environment STAR_USER_REGISTRY
    OString sBuffer( getenv(USER_REGISTRY_NAME_ENV) );
    if ( sBuffer.getLength() > 0 )
    {
        f = fopen( sBuffer.getStr(), "r" );

        if (f != NULL)
        {
            fclose(f);
            userRegistryName = OStringToOUString( sBuffer, osl_getThreadTextEncoding() );
        }
    }

    if ( !userRegistryName.getLength() )
    {
        userRegistryName = getDefaultLocalRegistry();
    }

    return userRegistryName;
}

OUString getPathToSystemRegistry()
{
    OUString uBuffer;
    OUString registryBaseName( RTL_CONSTASCII_USTRINGPARAM(REGISTRY_SYSTEM_NAME) );
    OUString systemRegistryName;
    FILE     *f=NULL;

    // search in the directory of the executable
    if( OStartupInfo::E_None == OStartupInfo().getExecutableFile(uBuffer) )
    {
        sal_uInt32  lastIndex = uBuffer.lastIndexOf(PATH_DELEMITTER);
        if (lastIndex > 0)
        {
            uBuffer = uBuffer.copy(0, lastIndex + 1);
        }

        uBuffer += registryBaseName;

        if (!FileBase::getSystemPathFromFileURL(uBuffer, systemRegistryName))
        {
            OString tmpStr( OUStringToOString(systemRegistryName, osl_getThreadTextEncoding()) );
            f = fopen( tmpStr.getStr(), "r" );
        }
    }

    if (f == NULL)
    {
        // search the environment STAR_REGISTRY
        OString tmpStr( getenv(SYSTEM_REGISTRY_NAME_ENV) );
        if ( tmpStr.getLength() > 0 )
        {
            f = fopen(tmpStr.getStr(), "r");

            if (f != NULL)
            {
                fclose(f);
                systemRegistryName = OStringToOUString( tmpStr, osl_getThreadTextEncoding() );
            } else
            {
                systemRegistryName = OUString();
            }
        }
    } else
    {
        fclose(f);
    }

    return systemRegistryName;
}

}

<commit_msg>INTEGRATION: CWS ooo19126 (1.13.150); FILE MERGED 2005/09/05 15:24:02 rt 1.13.150.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: regpathhelper.cxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 02:52:13 $
 *
 *  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
 *
 ************************************************************************/

#include <stdio.h>

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _OSL_SECURITY_HXX_
#include <osl/security.hxx>
#endif
#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif
#ifndef _VOS_PROCESS_HXX_
#include <vos/process.hxx>
#endif
#ifndef _RTL_TEXTENC_H
#include <rtl/textenc.h>
#endif
#ifndef _RTL_URI_H_
#include <rtl/uri.h>
#endif
#ifndef _RTL_URI_HXX_
#include <rtl/uri.hxx>
#endif

using namespace vos;
using namespace osl;
using namespace rtl;

#define PATH_DELEMITTER '/'

#define USER_REGISTRY_NAME_ENV      "STAR_USER_REGISTRY"
#define SYSTEM_REGISTRY_NAME_ENV    "STAR_REGISTRY"
#define REGISTRY_SYSTEM_NAME    "services.rdb"

#define REGISTRY_LOCAL_NAME     "user60.rdb"

#ifdef SAL_UNX
#define CONFIG_PATH_PREFIX      "."
#else
#define CONFIG_PATH_PREFIX      ""
#endif

namespace comphelper
{

/**
   @return sal_True, if the office is started in a portal
                     environment.
           sal_False, if the common office is started
 */
static sal_Bool retrievePortalUserDir( OUString *pDirectory )
{
    OStartupInfo startInfo;
    sal_uInt32 nArgs = startInfo.getCommandArgCount();
    sal_Bool bIsPortalUser = sal_False;
    OUString sArg;
    while( nArgs > 0 )
      {
        if ( !startInfo.getCommandArg(--nArgs, sArg) )
          {
            if ( sArg.indexOf(OUString::createFromAscii("-userid")) == 0 )
            {

                  bIsPortalUser = sal_True;
                sal_Int32 nStart = sArg.lastIndexOf( '[' );
                sal_Int32 nEnd   = sArg.lastIndexOf( ']' );
                if( -1 == nStart || -1 == nEnd || nEnd < nStart)
                {
                    *pDirectory = OUString();
                }
                else
                {
                    OUString aEncHome = sArg.copy( nStart + 1 , nEnd - nStart -1 );
                    *pDirectory = rtl::Uri::decode(aEncHome,
                                                   rtl_UriDecodeWithCharset,
                                                   RTL_TEXTENCODING_UTF8);
                }
                  break;
            }
          }
     }
    return bIsPortalUser;
}

static OUString getDefaultLocalRegistry()
{
    OUString uBuffer, userRegistryName;
    OUString portalUserDir;

    sal_Bool bIsPortalUser = retrievePortalUserDir( &portalUserDir );

    if ( bIsPortalUser )
       {
        if(  portalUserDir.getLength() )
        {
            FileBase::getFileURLFromSystemPath( portalUserDir , portalUserDir );
            userRegistryName = portalUserDir;
            userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
                "/user/" REGISTRY_LOCAL_NAME ) );

            // Directory creation is probably necessary for bootstrapping a new
            // user in the portal environment (the ucb uses this function).
            // This should be solved differently, as
            // no one expects this function to create anything ...
            OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
            OUString sPath(RTL_CONSTASCII_USTRINGPARAM("file://"));
            FileBase::RC retRC = FileBase::E_None;

            sal_Int32 nIndex = 3;
            sPath += userRegistryName.getToken(2, '/', nIndex);
            while( nIndex != -1 )
            {
                sPath += sSeparator;
                sPath += userRegistryName.getToken(0, '/', nIndex);
                if( nIndex == -1 )
                    break;
                Directory aDir( sPath );
                if( aDir.open() == FileBase::E_NOENT )
                {
                    retRC = Directory::create(sPath);
                    if ( retRC != FileBase::E_None && retRC != FileBase::E_EXIST)
                    {
                        return OUString();
                    }
                }
            }
        }
    }
    else /* bIsPortalUser */
    {
        ::osl::Security aUserSecurity;
        aUserSecurity.getConfigDir( userRegistryName );
        userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
            "/" CONFIG_PATH_PREFIX REGISTRY_LOCAL_NAME ) );
    }

    return userRegistryName;
}

OUString getPathToUserRegistry()
{
    OUString    userRegistryName;
    FILE        *f=NULL;

    // search the environment STAR_USER_REGISTRY
    OString sBuffer( getenv(USER_REGISTRY_NAME_ENV) );
    if ( sBuffer.getLength() > 0 )
    {
        f = fopen( sBuffer.getStr(), "r" );

        if (f != NULL)
        {
            fclose(f);
            userRegistryName = OStringToOUString( sBuffer, osl_getThreadTextEncoding() );
        }
    }

    if ( !userRegistryName.getLength() )
    {
        userRegistryName = getDefaultLocalRegistry();
    }

    return userRegistryName;
}

OUString getPathToSystemRegistry()
{
    OUString uBuffer;
    OUString registryBaseName( RTL_CONSTASCII_USTRINGPARAM(REGISTRY_SYSTEM_NAME) );
    OUString systemRegistryName;
    FILE     *f=NULL;

    // search in the directory of the executable
    if( OStartupInfo::E_None == OStartupInfo().getExecutableFile(uBuffer) )
    {
        sal_uInt32  lastIndex = uBuffer.lastIndexOf(PATH_DELEMITTER);
        if (lastIndex > 0)
        {
            uBuffer = uBuffer.copy(0, lastIndex + 1);
        }

        uBuffer += registryBaseName;

        if (!FileBase::getSystemPathFromFileURL(uBuffer, systemRegistryName))
        {
            OString tmpStr( OUStringToOString(systemRegistryName, osl_getThreadTextEncoding()) );
            f = fopen( tmpStr.getStr(), "r" );
        }
    }

    if (f == NULL)
    {
        // search the environment STAR_REGISTRY
        OString tmpStr( getenv(SYSTEM_REGISTRY_NAME_ENV) );
        if ( tmpStr.getLength() > 0 )
        {
            f = fopen(tmpStr.getStr(), "r");

            if (f != NULL)
            {
                fclose(f);
                systemRegistryName = OStringToOUString( tmpStr, osl_getThreadTextEncoding() );
            } else
            {
                systemRegistryName = OUString();
            }
        }
    } else
    {
        fclose(f);
    }

    return systemRegistryName;
}

}

<|endoftext|>