text:
/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file State.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include <secp256k1.h>
#include <boost/filesystem.hpp>
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#if WIN32
#pragma warning(pop)
#else
#endif
#include <time.h>
#include <random>
#include "BlockChain.h"
#include "Instruction.h"
#include "Exceptions.h"
#include "Dagger.h"
#include "State.h"
using namespace std;
using namespace eth;

u256 const State::c_stepFee = 10000;
u256 const State::c_dataFee = 20000;
u256 const State::c_memoryFee = 30000;
u256 const State::c_extroFee = 40000;
u256 const State::c_cryptoFee = 50000;
u256 const State::c_newContractFee = 60000;
u256 const State::c_txFee = 0;
u256 const State::c_blockReward = 1000000000;

#if NDEBUG
u256 const eth::c_genesisDifficulty = (u256)1 << 22;
#else
u256 const eth::c_genesisDifficulty = (u256)1 << 22;
#endif

std::map<Address, AddressState> const& eth::genesisState()
{
	static std::map<Address, AddressState> s_ret;
	if (s_ret.empty())
	{
		// Initialise.
		s_ret[Address(fromUserHex("812413ae7e515a3bcaf7b3444116527bce958c02"))] = AddressState(u256(1) << 200, 0);
		s_ret[Address(fromUserHex("93658b04240e4bd4046fd2d6d417d20f146f4b43"))] = AddressState(u256(1) << 200, 0);
	}
	return s_ret;
}

Overlay State::openDB(std::string _path, bool _killExisting)
{
	if (_path.empty())
		_path = Defaults::s_dbPath;
	boost::filesystem::create_directory(_path);
	if (_killExisting)
		boost::filesystem::remove_all(_path + "/state");

	ldb::Options o;
	o.create_if_missing = true;
	ldb::DB* db = nullptr;
	ldb::DB::Open(o, _path + "/state", &db);
	return Overlay(db);
}

State::State(Address _coinbaseAddress, Overlay const& _db): m_db(_db), m_state(&m_db), m_ourAddress(_coinbaseAddress)
{
	secp256k1_start();

	// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
	m_state.init();
	eth::commit(genesisState(), m_db, m_state);
	cout << "State::State: state root initialised to " << m_state.root() << endl;

	m_previousBlock = BlockInfo::genesis();
	cnote << "Genesis headerhash-nononce:" << m_previousBlock.headerHashWithoutNonce();
	{
		RLPStream s;
		m_previousBlock.fillStream(s, false);
		cnote << RLP(s.out());
		cnote << asHex(s.out());
	}
	resetCurrent();

	assert(m_state.root() == m_previousBlock.stateRoot);
}

void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
{
	auto it = m_cache.find(_a);
	if (it == m_cache.end())
	{
		// populate basic info.
		string stateBack = m_state.at(_a);
		if (stateBack.empty() && !_forceCreate)
			return;
		RLP state(stateBack);
		AddressState s;
		if (state.isNull())
			s = AddressState(0, 0);
		else if (state.itemCount() == 2)
			s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>());
		else
			s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>());
		bool ok;
		tie(it, ok) = m_cache.insert(make_pair(_a, s));
	}
	if (_requireMemory && !it->second.haveMemory())
	{
		// Populate memory.
		assert(it->second.type() == AddressType::Contract);
		TrieDB<u256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot());		// promise we won't alter the overlay! :)
		map<u256, u256>& mem = it->second.takeMemory();
		for (auto const& i: memdb)
			if (mem.find(i.first) == mem.end())
				mem.insert(make_pair(i.first, RLP(i.second).toInt<u256>()));
			else
				mem.at(i.first) = RLP(i.second).toInt<u256>();
	}
}

void State::commit()
{
	eth::commit(m_cache, m_db, m_state);
	m_cache.clear();
}

bool State::sync(BlockChain const& _bc)
{
	return sync(_bc, _bc.currentHash());
}

bool State::sync(BlockChain const& _bc, h256 _block)
{
	bool ret = false;
	// BLOCK
	BlockInfo bi;
	try
	{
		auto b = _bc.block(_block);
		bi.populate(b);
		bi.verifyInternals(_bc.block(_block));
	}
	catch (...)
	{
		// TODO: Slightly nicer handling? :-)
		cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
		exit(1);
	}

	if (bi == m_currentBlock)
	{
		// We mined the last block.
		// Our state is good - we just need to move on to next.
		m_previousBlock = m_currentBlock;
		resetCurrent();
		m_currentNumber++;
		ret = true;
	}
	else if (bi == m_previousBlock)
	{
		// No change since last sync.
		// Carry on as we were.
	}
	else
	{
		// New blocks available, or we've switched to a different branch. All change.
		// Find most recent state dump and replay what's left.
		// (Most recent state dump might end up being genesis.)

		std::vector<h256> chain;
		while (bi.stateRoot != BlockInfo::genesis().hash && m_db.lookup(bi.stateRoot).empty())	// while we don't have the state root of the latest block...
		{
			chain.push_back(bi.hash);				// push back for later replay.
			bi.populate(_bc.block(bi.parentHash));	// move to parent.
		}

		m_previousBlock = bi;
		resetCurrent();

		// Iterate through in reverse, playing back each of the blocks.
		for (auto it = chain.rbegin(); it != chain.rend(); ++it)
			playback(_bc.block(*it), true);

		m_currentNumber = _bc.details(_block).number + 1;
		resetCurrent();
		ret = true;
	}
	return ret;
}

map<Address, u256> State::addresses() const
{
	map<Address, u256> ret;
	for (auto i: m_cache)
		if (i.second.type() != AddressType::Dead)
			ret[i.first] = i.second.balance();
	for (auto const& i: m_state)
		if (m_cache.find(i.first) == m_cache.end())
			ret[i.first] = RLP(i.second)[0].toInt<u256>();
	return ret;
}

void State::resetCurrent()
{
	m_transactions.clear();
	m_cache.clear();
	m_currentBlock = BlockInfo();
	m_currentBlock.coinbaseAddress = m_ourAddress;
	m_currentBlock.stateRoot = m_previousBlock.stateRoot;
	m_currentBlock.parentHash = m_previousBlock.hash;
	m_state.setRoot(m_currentBlock.stateRoot);
}

bool State::sync(TransactionQueue& _tq)
{
	// TRANSACTIONS
	bool ret = false;
	auto ts = _tq.transactions();
	for (auto const& i: ts)
		if (!m_transactions.count(i.first))
			// don't have it yet! Execute it now.
			try
			{
				execute(i.second);
				ret = true;
			}
			catch (InvalidNonce const& in)
			{
				if (in.required > in.candidate)
				{
					// too old
					_tq.drop(i.first);
					ret = true;
				}
			}
			catch (std::exception const&)
			{
				// Something else went wrong - drop it.
				_tq.drop(i.first);
				ret = true;
			}
	return ret;
}

u256 State::playback(bytesConstRef _block, bool _fullCommit)
{
	try
	{
		m_currentBlock.populate(_block);
		m_currentBlock.verifyInternals(_block);
		return playback(_block, BlockInfo(), _fullCommit);
	}
	catch (...)
	{
		// TODO: Slightly nicer handling? :-)
		cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
		exit(1);
	}
}

u256 State::playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit)
{
	m_currentBlock = _bi;
	m_previousBlock = _parent;
	return playback(_block, _grandParent, _fullCommit);
}

u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit)
{
	if (m_currentBlock.parentHash != m_previousBlock.hash)
		throw InvalidParentHash();

	// All ok with the block generally. Play back the transactions now...
	for (auto const& i: RLP(_block)[1])
		execute(i.data());

	// Initialise total difficulty calculation.
	u256 tdIncrease = m_currentBlock.difficulty;

	// Check uncles & apply their rewards to state.
	Addresses rewarded;
	for (auto const& i: RLP(_block)[2])
	{
		BlockInfo uncle(i.data());
		if (m_previousBlock.parentHash != uncle.parentHash)
			throw InvalidUncle();
		if (_grandParent)
			uncle.verifyParent(_grandParent);
		tdIncrease += uncle.difficulty;
		rewarded.push_back(uncle.coinbaseAddress);
	}
	applyRewards(rewarded);

	// Commit all cached state changes to the state trie.
	commit();

	// Hash the state trie and check against the state_root hash in m_currentBlock.
	if (m_currentBlock.stateRoot != rootHash())
	{
		cout << "*** BAD STATE ROOT!" << endl;
		cout << m_state << endl << TrieDB<Address, Overlay>(&m_db, m_currentBlock.stateRoot);
		// Rollback the trie.
		m_db.rollback();
		throw InvalidStateRoot();
	}

	if (_fullCommit)
	{
		// Commit the new trie to disk.
		m_db.commit();

		m_previousBlock = m_currentBlock;
		resetCurrent();
	}
	else
	{
		m_db.rollback();
		resetCurrent();
	}

	return tdIncrease;
}

// @returns the block that represents the difference between m_previousBlock and m_currentBlock.
// (i.e. all the transactions we executed).
void State::commitToMine(BlockChain const& _bc)
{
	if (m_currentBlock.sha3Transactions != h256() || m_currentBlock.sha3Uncles != h256())
		return;

	RLPStream uncles;
	Addresses uncleAddresses;

	if (m_previousBlock != BlockInfo::genesis())
	{
		// Find uncles if we're not a direct child of the genesis.
//		cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl;
		auto us = _bc.details(m_previousBlock.parentHash).children;
		assert(us.size() >= 1);	// must be at least 1 child of our grandparent - it's our own parent!
		uncles.appendList(us.size() - 1);	// one fewer - uncles precludes our parent from the list of grandparent's children.
		for (auto const& u: us)
			if (u != m_previousBlock.hash)	// ignore our own parent - it's not an uncle.
			{
				BlockInfo ubi(_bc.block(u));
				ubi.fillStream(uncles, true);
				uncleAddresses.push_back(ubi.coinbaseAddress);
			}
	}
	else
		uncles.appendList(0);

	applyRewards(uncleAddresses);

	RLPStream txs(m_transactions.size());
	for (auto const& i: m_transactions)
		i.second.fillStream(txs);

	txs.swapOut(m_currentTxs);
	uncles.swapOut(m_currentUncles);

	m_currentBlock.sha3Transactions = sha3(m_currentTxs);
	m_currentBlock.sha3Uncles = sha3(m_currentUncles);

	// Commit any and all changes to the trie that are in the cache, then update the state root accordingly.
	commit();
	m_currentBlock.stateRoot = m_state.root();
	m_currentBlock.parentHash = m_previousBlock.hash;
}

MineInfo State::mine(uint _msTimeout)
{
	// Update timestamp according to clock.
	m_currentBlock.timestamp = time(0);

	// Update difficulty according to timestamp.
	m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);

	// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
	MineInfo ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout);
	if (ret.completed)
	{
		// Got it!

		// Commit to disk.
		m_db.commit();

		// Compile block:
		RLPStream ret;
		ret.appendList(3);
		m_currentBlock.fillStream(ret, true);
		ret.appendRaw(m_currentTxs);
		ret.appendRaw(m_currentUncles);
		ret.swapOut(m_currentBytes);
		m_currentBlock.hash = sha3(m_currentBytes);
		cout << "*** SUCCESS: Mined " << m_currentBlock.hash << " (parent: " << m_currentBlock.parentHash << ")" << endl;
	}
	else
		m_currentBytes.clear();

	return ret;
}

bool State::isNormalAddress(Address _id) const
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end())
		return false;
	return it->second.type() == AddressType::Normal;
}

bool State::isContractAddress(Address _id) const
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end())
		return false;
	return it->second.type() == AddressType::Contract;
}

u256 State::balance(Address _id) const
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end())
		return 0;
	return it->second.balance();
}

void State::noteSending(Address _id)
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end())
		m_cache[_id] = AddressState(0, 1);
	else
		it->second.incNonce();
}

void State::addBalance(Address _id, u256 _amount)
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end())
		m_cache[_id] = AddressState(_amount, 0);
	else
		it->second.addBalance(_amount);
}

void State::subBalance(Address _id, bigint _amount)
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end() || (bigint)it->second.balance() < _amount)
		throw NotEnoughCash();
	else
		it->second.addBalance(-_amount);
}

u256 State::transactionsFrom(Address _id) const
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end())
		return 0;
	else
		return it->second.nonce();
}

u256 State::contractMemory(Address _id, u256 _memory) const
{
	ensureCached(_id, false, false);
	auto it = m_cache.find(_id);
	if (it == m_cache.end() || it->second.type() != AddressType::Contract)
		return 0;
	else if (it->second.haveMemory())
	{
		auto mit = it->second.memory().find(_memory);
		if (mit == it->second.memory().end())
			return 0;
		return mit->second;
	}
	// Memory not cached - just grab one item from the DB rather than cache the lot.
	TrieDB<u256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot());			// promise we won't change the overlay! :)
	return RLP(memdb.at(_memory)).toInt<u256>();	// TODO: CHECK: check if this is actually an RLP decode
}

void State::execute(bytesConstRef _rlp)
{
	// Entry point for a user-executed transaction.
	Transaction t(_rlp);
	executeBare(t, t.sender());

	// Add to the user-originated transactions that we've executed.
	// NOTE: Here, contract-originated transactions will not get added to the transaction list.
	// If this is wrong, move this line into execute(Transaction const& _t, Address _sender) and
	// don't forget to allow unsigned transactions in the tx list if they concur with the script execution.
	m_transactions.insert(make_pair(t.sha3(), t));
}

void State::applyRewards(Addresses const& _uncleAddresses)
{
	u256 r = c_blockReward;
	for (auto const& i: _uncleAddresses)
	{
		addBalance(i, c_blockReward * 4 / 3);
		r += c_blockReward / 8;
	}
	addBalance(m_currentBlock.coinbaseAddress, r);
}

void State::executeBare(Transaction const& _t, Address _sender)
{
	// Entry point for a contract-originated transaction.

	// Ignore invalid transactions.
	auto nonceReq = transactionsFrom(_sender);
	if (_t.nonce != nonceReq)
		throw InvalidNonce(nonceReq, _t.nonce);

	// Not considered invalid - just pointless.
	if (balance(_sender) < _t.value + _t.fee)
		throw NotEnoughCash();

	// TODO: check fee is sufficient?

	// Increment associated nonce for sender.
	noteSending(_sender);

	if (_t.receiveAddress)
	{
		subBalance(_sender, _t.value + _t.fee);
		addBalance(_t.receiveAddress, _t.value);
		addBalance(m_currentBlock.coinbaseAddress, _t.fee);

		if (isContractAddress(_t.receiveAddress))
		{
			MinerFeeAdder feeAdder({this, 0});	// will add fee on destruction.
			execute(_t.receiveAddress, _sender, _t.value, _t.fee, _t.data, &feeAdder.fee);
		}
	}
	else
	{
		// Try to make a new contract
		if (_t.fee < _t.data.size() * c_memoryFee + c_newContractFee)
			throw FeeTooSmall();

		Address newAddress = low160(_t.sha3());

		if (isContractAddress(newAddress) || isNormalAddress(newAddress))
			throw ContractAddressCollision();

		// All OK - set it up.
		m_cache[newAddress] = AddressState(0, 0, sha3(RLPNull));
		auto& mem = m_cache[newAddress].takeMemory();
		for (uint i = 0; i < _t.data.size(); ++i)
			if (mem.find(i) == mem.end())
				mem.insert(make_pair(i, _t.data[i]));
			else
				mem.at(i) = _t.data[i];

		subBalance(_sender, _t.value + _t.fee);
		addBalance(newAddress, _t.value);
		addBalance(m_currentBlock.coinbaseAddress, _t.fee);
	}
}

// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
// Currently we just pull out the left (high-order in BE) 160-bits.
// TODO: CHECK: check that this is correct.
inline Address asAddress(u256 _item)
{
	return left160(h256(_item));
}

void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee)
{
	std::vector<u256> stack;

	// Set up some local functions.
	auto require = [&](u256 _n)
	{
		if (stack.size() < _n)
			throw StackTooSmall(_n, stack.size());
	};
	ensureCached(_myAddress, true, true);
	auto& myMemory = m_cache[_myAddress].takeMemory();

	auto mem = [&](u256 _n) -> u256
	{
		auto i = myMemory.find(_n);
		return i == myMemory.end() ? 0 : i->second;
	};
	auto setMem = [&](u256 _n, u256 _v)
	{
		if (_v)
		{
			auto it = myMemory.find(_n);
			if (it == myMemory.end())
				myMemory.insert(make_pair(_n, _v));
			else
				myMemory.at(_n) = _v;
		}
		else
			myMemory.erase(_n);
	};

	u256 curPC = 0;
	u256 nextPC = 1;
	u256 stepCount = 0;
	for (bool stopped = false; !stopped; curPC = nextPC, nextPC = curPC + 1)
	{
		stepCount++;

		bigint minerFee = stepCount > 16 ? c_stepFee : 0;
		bigint voidFee = 0;

		auto rawInst = mem(curPC);
		if (rawInst > 0xff)
			throw BadInstruction();
		Instruction inst = (Instruction)(uint8_t)rawInst;

		switch (inst)
		{
		case Instruction::STORE:
			require(2);
			if (!mem(stack.back()) && stack[stack.size() - 2])
				voidFee += c_memoryFee;
			if (mem(stack.back()) && !stack[stack.size() - 2])
				voidFee -= c_memoryFee;
			// continue on to...
		case Instruction::LOAD:
			minerFee += c_dataFee;
			break;

		case Instruction::EXTRO:
		case Instruction::BALANCE:
			minerFee += c_extroFee;
			break;

		case Instruction::MKTX:
			minerFee += c_txFee;
			break;

		case Instruction::SHA256:
		case Instruction::RIPEMD160:
		case Instruction::ECMUL:
		case Instruction::ECADD:
		case Instruction::ECSIGN:
		case Instruction::ECRECOVER:
		case Instruction::ECVALID:
			minerFee += c_cryptoFee;
			break;
		default:
			break;
		}

		if (minerFee + voidFee > balance(_myAddress))
			throw NotEnoughCash();
		subBalance(_myAddress, minerFee + voidFee);
		*_totalFee += (u256)minerFee;

		switch (inst)
		{
		case Instruction::ADD:
			//pops two items and pushes S[-1] + S[-2] mod 2^256.
			require(2);
			stack[stack.size() - 2] += stack.back();
			stack.pop_back();
			break;
		case Instruction::MUL:
			//pops two items and pushes S[-1] * S[-2] mod 2^256.
			require(2);
			stack[stack.size() - 2] *= stack.back();
			stack.pop_back();
			break;
		case Instruction::SUB:
			require(2);
			stack[stack.size() - 2] = stack.back() - stack[stack.size() - 2];
			stack.pop_back();
			break;
		case Instruction::DIV:
			require(2);
			stack[stack.size() - 2] = stack.back() / stack[stack.size() - 2];
			stack.pop_back();
			break;
		case Instruction::SDIV:
			require(2);
			(s256&)stack[stack.size() - 2] = (s256&)stack.back() / (s256&)stack[stack.size() - 2];
			stack.pop_back();
			break;
		case Instruction::MOD:
			require(2);
			stack[stack.size() - 2] = stack.back() % stack[stack.size() - 2];
			stack.pop_back();
			break;
		case Instruction::SMOD:
			require(2);
			(s256&)stack[stack.size() - 2] = (s256&)stack.back() % (s256&)stack[stack.size() - 2];
			stack.pop_back();
			break;
		case Instruction::EXP:
		{
			// TODO: better implementation?
			require(2);
			auto n = stack.back();
			auto x = stack[stack.size() - 2];
			stack.pop_back();
			for (u256 i = 0; i < x; ++i)
				n *= n;
			stack.back() = n;
			break;
		}
		case Instruction::NEG:
			require(1);
			stack.back() = ~(stack.back() - 1);
			break;
		case Instruction::LT:
			require(2);
			stack[stack.size() - 2] = stack.back() < stack[stack.size() - 2] ? 1 : 0;
			stack.pop_back();
			break;
		case Instruction::LE:
			require(2);
			stack[stack.size() - 2] = stack.back() <= stack[stack.size() - 2] ? 1 : 0;
			stack.pop_back();
			break;
		case Instruction::GT:
			require(2);
			stack[stack.size() - 2] = stack.back() > stack[stack.size() - 2] ? 1 : 0;
			stack.pop_back();
			break;
		case Instruction::GE:
			require(2);
			stack[stack.size() - 2] = stack.back() >= stack[stack.size() - 2] ? 1 : 0;
			stack.pop_back();
			break;
		case Instruction::EQ:
			require(2);
			stack[stack.size() - 2] = stack.back() == stack[stack.size() - 2] ? 1 : 0;
			stack.pop_back();
			break;
		case Instruction::NOT:
			require(1);
			stack.back() = stack.back() ? 0 : 1;
			stack.pop_back();
			break;
		case Instruction::MYADDRESS:
			stack.push_back((u160)_myAddress);
			break;
		case Instruction::TXSENDER:
			stack.push_back((u160)_txSender);
			break;
		case Instruction::TXVALUE:
			stack.push_back(_txValue);
			break;
		case Instruction::TXFEE:
			stack.push_back(_txFee);
			break;
		case Instruction::TXDATAN:
			stack.push_back(_txData.size());
			break;
		case Instruction::TXDATA:
			require(1);
			stack.back() = stack.back() < _txData.size() ? _txData[(uint)stack.back()] : 0;
			break;
		case Instruction::BLK_PREVHASH:
			stack.push_back(m_previousBlock.hash);
			break;
		case Instruction::BLK_COINBASE:
			stack.push_back((u160)m_currentBlock.coinbaseAddress);
			break;
		case Instruction::BLK_TIMESTAMP:
			stack.push_back(m_currentBlock.timestamp);
			break;
		case Instruction::BLK_NUMBER:
			stack.push_back(m_currentNumber);
			break;
		case Instruction::BLK_DIFFICULTY:
			stack.push_back(m_currentBlock.difficulty);
			break;
		case Instruction::SHA256:
		{
			uint s = (uint)min(stack.back(), (u256)(stack.size() - 1) * 32);
			stack.pop_back();

			CryptoPP::SHA256 digest;
			uint i = 0;
			for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
			{
				bytes b = toBigEndian(stack.back());
				digest.Update(b.data(), (int)min<u256>(32, s));			// b.size() == 32
				stack.pop_back();
			}
			array<byte, 32> final;
			digest.TruncatedFinal(final.data(), 32);
			stack.push_back(fromBigEndian<u256>(final));
			break;
		}
		case Instruction::RIPEMD160:
		{
			uint s = (uint)min(stack.back(), (u256)(stack.size() - 1) * 32);
			stack.pop_back();

			CryptoPP::RIPEMD160 digest;
			uint i = 0;
			for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
			{
				bytes b = toBigEndian(stack.back());
				digest.Update(b.data(), (int)min<u256>(32, s));			// b.size() == 32
				stack.pop_back();
			}
			array<byte, 20> final;
			digest.TruncatedFinal(final.data(), 20);
			// NOTE: this aligns to right of 256-bit container (low-order bytes).
			// This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
			stack.push_back((u256)fromBigEndian<u160>(final));
			break;
		}
		case Instruction::ECMUL:
		{
			// ECMUL - pops three items.
			// If (S[-2],S[-1]) are a valid point in secp256k1, including both coordinates being less than P, pushes (S[-1],S[-2]) * S[-3], using (0,0) as the point at infinity.
			// Otherwise, pushes (0,0).
			require(3);

			bytes pub(1, 4);
			pub += toBigEndian(stack[stack.size() - 2]);
			pub += toBigEndian(stack.back());
			stack.pop_back();
			stack.pop_back();

			bytes x = toBigEndian(stack.back());
			stack.pop_back();

			if (secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size()))	// TODO: Check both are less than P.
			{
				secp256k1_ecdsa_pubkey_tweak_mul(pub.data(), (int)pub.size(), x.data());
				stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(1, 32)));
				stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(33, 32)));
			}
			else
			{
				stack.push_back(0);
				stack.push_back(0);
			}
			break;
		}
		case Instruction::ECADD:
		{
			// ECADD - pops four items and pushes (S[-4],S[-3]) + (S[-2],S[-1]) if both points are valid, otherwise (0,0).
			require(4);

			bytes pub(1, 4);
			pub += toBigEndian(stack[stack.size() - 2]);
			pub += toBigEndian(stack.back());
			stack.pop_back();
			stack.pop_back();

			bytes tweak(1, 4);
			tweak += toBigEndian(stack[stack.size() - 2]);
			tweak += toBigEndian(stack.back());
			stack.pop_back();
			stack.pop_back();

			if (secp256k1_ecdsa_pubkey_verify(pub.data(),(int) pub.size()) && secp256k1_ecdsa_pubkey_verify(tweak.data(),(int) tweak.size()))
			{
				secp256k1_ecdsa_pubkey_tweak_add(pub.data(), (int)pub.size(), tweak.data());
				stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(1, 32)));
				stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(33, 32)));
			}
			else
			{
				stack.push_back(0);
				stack.push_back(0);
			}
			break;
		}
		case Instruction::ECSIGN:
		{
			require(2);
			bytes sig(64);
			int v = 0;

			u256 msg = stack.back();
			stack.pop_back();
			u256 priv = stack.back();
			stack.pop_back();
			bytes nonce = toBigEndian(Transaction::kFromMessage(msg, priv));

			if (!secp256k1_ecdsa_sign_compact(toBigEndian(msg).data(), 64, sig.data(), toBigEndian(priv).data(), nonce.data(), &v))
				throw InvalidSignature();

			stack.push_back(v + 27);
			stack.push_back(fromBigEndian<u256>(bytesConstRef(&sig).cropped(0, 32)));
			stack.push_back(fromBigEndian<u256>(bytesConstRef(&sig).cropped(32)));
			break;
		}
		case Instruction::ECRECOVER:
		{
			require(4);

			bytes sig = toBigEndian(stack[stack.size() - 2]) + toBigEndian(stack.back());
			stack.pop_back();
			stack.pop_back();
			int v = (int)stack.back();
			stack.pop_back();
			bytes msg = toBigEndian(stack.back());
			stack.pop_back();

			byte pubkey[65];
			int pubkeylen = 65;
			if (secp256k1_ecdsa_recover_compact(msg.data(), (int)msg.size(), sig.data(), pubkey, &pubkeylen, 0, v - 27))
			{
				stack.push_back(0);
				stack.push_back(0);
			}
			else
			{
				stack.push_back(fromBigEndian<u256>(bytesConstRef(&pubkey[1], 32)));
				stack.push_back(fromBigEndian<u256>(bytesConstRef(&pubkey[33], 32)));
			}
			break;
		}
		case Instruction::ECVALID:
		{
			require(2);
			bytes pub(1, 4);
			pub += toBigEndian(stack[stack.size() - 2]);
			pub += toBigEndian(stack.back());
			stack.pop_back();
			stack.pop_back();

			stack.back() = secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size()) ? 1 : 0;
			break;
		}
		case Instruction::SHA3:
		{
			uint s = (uint)min(stack.back(), (u256)(stack.size() - 1) * 32);
			stack.pop_back();

			CryptoPP::SHA3_256 digest;
			uint i = 0;
			for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
			{
				bytes b = toBigEndian(stack.back());
				digest.Update(b.data(), (int)min<u256>(32, s));			// b.size() == 32
				stack.pop_back();
			}
			array<byte, 32> final;
			digest.TruncatedFinal(final.data(), 32);
			stack.push_back(fromBigEndian<u256>(final));
			break;
		}
		case Instruction::PUSH:
		{
			stack.push_back(mem(curPC + 1));
			nextPC = curPC + 2;
			break;
		}
		case Instruction::POP:
			require(1);
			stack.pop_back();
			break;
		case Instruction::DUP:
			require(1);
			stack.push_back(stack.back());
			break;
		case Instruction::DUPN:
		{
			auto s = mem(curPC + 1);
			if (s == 0 || s > stack.size())
				throw OperandOutOfRange(1, stack.size(), s);
			stack.push_back(stack[stack.size() - (uint)s]);
			nextPC = curPC + 2;
			break;
		}
		case Instruction::SWAP:
		{
			require(2);
			auto d = stack.back();
			stack.back() = stack[stack.size() - 2];
			stack[stack.size() - 2] = d;
			break;
		}
		case Instruction::SWAPN:
		{
			require(1);
			auto d = stack.back();
			auto s = mem(curPC + 1);
			if (s == 0 || s > stack.size())
				throw OperandOutOfRange(1, stack.size(), s);
			stack.back() = stack[stack.size() - (uint)s];
			stack[stack.size() - (uint)s] = d;
			nextPC = curPC + 2;
			break;
		}
		case Instruction::LOAD:
			require(1);
			stack.back() = mem(stack.back());
			break;
		case Instruction::STORE:
			require(2);
			setMem(stack.back(), stack[stack.size() - 2]);
			stack.pop_back();
			stack.pop_back();
			break;
		case Instruction::JMP:
			require(1);
			nextPC = stack.back();
			stack.pop_back();
			break;
		case Instruction::JMPI:
			require(2);
			if (stack.back())
				nextPC = stack[stack.size() - 2];
			stack.pop_back();
			stack.pop_back();
			break;
		case Instruction::IND:
			stack.push_back(curPC);
			break;
		case Instruction::EXTRO:
		{
			require(2);
			auto memoryAddress = stack.back();
			stack.pop_back();
			Address contractAddress = asAddress(stack.back());
			stack.back() = contractMemory(contractAddress, memoryAddress);
			break;
		}
		case Instruction::BALANCE:
		{
			require(1);
			stack.back() = balance(asAddress(stack.back()));
			break;
		}
		case Instruction::MKTX:
		{
			require(4);

			Transaction t;
			t.receiveAddress = asAddress(stack.back());
			stack.pop_back();
			t.value = stack.back();
			stack.pop_back();
			t.fee = stack.back();
			stack.pop_back();

			auto itemCount = stack.back();
			stack.pop_back();
			if (stack.size() < itemCount)
				throw OperandOutOfRange(0, stack.size(), itemCount);
			t.data.reserve((uint)itemCount);
			for (auto i = 0; i < itemCount; ++i)
			{
				t.data.push_back(stack.back());
				stack.pop_back();
			}

			t.nonce = transactionsFrom(_myAddress);
			executeBare(t, _myAddress);

			break;
		}
		case Instruction::SUICIDE:
		{
			require(1);
			Address dest = asAddress(stack.back());
			u256 minusVoidFee = myMemory.size() * c_memoryFee;
			addBalance(dest, balance(_myAddress) + minusVoidFee);
			m_cache[_myAddress].kill();
			// ...follow through to...
		}
		case Instruction::STOP:
			return;
		default:
			throw BadInstruction();
		}
	}
}

max_stars_repo_name: DldFw/ethereum

max_issues_repo_name: DldFw/ethereum

max_forks_repo_name: DldFw/ethereum


text:
/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
 *
 * 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 <boost/format.hpp>
#include <BrowserAssert.h>
#include <string>
#include "Config.h"
#include "CertificateStorage.h"
#include "Field.h"
#include "SQLTransactionScope.h"
#include "DBTools.h"
#include "SQLDatabase.h"
#include "SQLDatabaseImpl.h"
#include "DriverManager.h"
#include "StorageException.h"
#include "StorageExceptionInitialization.h"

namespace {
    const std::string TABLE_CERTIFICATE = "CERTIFICATE_TABLE";
    const std::string COL_PEM = "pem";
    const std::string COL_HOST = "host";
    const std::string COL_ALLOW = "allow";
    const std::string CONSTRAINT_TABLE_PK = TABLE_CERTIFICATE + "_PK";
    const std::string DDL_CREATE_TABLE_CERTIFICATE
                            = " CREATE TABLE " + TABLE_CERTIFICATE
                            + " ( " + COL_HOST + " TEXT,"
                            + "   " + COL_PEM + " TEXT,"
                            + "   " + COL_ALLOW + " INTEGER,"
                            + " CONSTRAINT " + CONSTRAINT_TABLE_PK
                            + "      PRIMARY KEY ( " + COL_HOST + " ) "
                            + "      ON CONFLICT REPLACE "
                            + " ); ";

}

namespace tizen_browser {
namespace storage {

CertificateStorage::CertificateStorage()
    : m_isInitialized(false)
    , m_dbCertificateInitialised(false)
{
    init();
}

CertificateStorage::~CertificateStorage()
{
}

void CertificateStorage::init()
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
    if (m_isInitialized)
        return;

    std::string resourceDbDir(boost::any_cast <std::string> (tizen_browser::config::Config::getInstance().get("resourcedb/dir")));
    std::string sessionDb(boost::any_cast <std::string> (tizen_browser::config::Config::getInstance().get("DB_CERTIFICATE")));

    DB_CERTIFICATE = resourceDbDir + sessionDb;

    BROWSER_LOGD("[%s:%d] DB_CERTIFICATE=%s", __PRETTY_FUNCTION__, __LINE__, DB_CERTIFICATE.c_str());

    try {
        initDatabaseCertificate(DB_CERTIFICATE);
    } catch (storage::StorageExceptionInitialization & e) {
        BROWSER_LOGE("[%s:%d] Cannot initialize database %s!", __PRETTY_FUNCTION__, __LINE__, DB_CERTIFICATE.c_str());
    }

    m_isInitialized = true;
}

void CertificateStorage::initDatabaseCertificate(const std::string& db_str)
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);

    if (!m_dbCertificateInitialised) {
        try {
            dbtools::checkAndCreateTable(db_str, TABLE_CERTIFICATE, DDL_CREATE_TABLE_CERTIFICATE);
        } catch (storage::StorageException & e) {
            throw storage::StorageExceptionInitialization(e.getMessage(),
                                                          e.getErrorCode());
        }

        m_dbCertificateInitialised = true;
    }

    M_ASSERT(m_dbCertificateInitialised);
}

std::shared_ptr<HostCertList> CertificateStorage::getHostCertList()
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
    auto hcList = std::make_shared<HostCertList>();
    int itemsCount = getCertificateEntriesCount();
    BROWSER_LOGD("Items count = %d", itemsCount);
    if (itemsCount != 0) {
        boost::format getCertificateString("SELECT %1%, %2% FROM %3% ;");
        getCertificateString % COL_HOST % COL_ALLOW % TABLE_CERTIFICATE;
        try {
            storage::SQLTransactionScope scope(storage::DriverManager::getDatabase(DB_CERTIFICATE));
            std::shared_ptr<storage::SQLDatabase> connection = scope.database();
            storage::SQLQuery getCertificateQuery(connection->prepare(getCertificateString.str()));
            getCertificateQuery.exec();
            for (int i = 0; i < itemsCount; ++i) {
                std::pair<std::string, int> hostCert = std::make_pair<std::string, int>(
                            getCertificateQuery.getString(0), getCertificateQuery.getInt(1));
                hcList->push_back(hostCert);
                getCertificateQuery.next();
            }
        } catch (storage::StorageException& e) {
            BROWSER_LOGD("[%s:%d] SQLException (%d): %s ", __PRETTY_FUNCTION__, __LINE__, e.getErrorCode(), e.getMessage());
        }
    }
    return hcList;
}

unsigned int CertificateStorage::getCertificateEntriesCount()
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
    boost::format getCountString("SELECT COUNT (*) FROM %1% ;");
    getCountString % TABLE_CERTIFICATE;
    try {
        storage::SQLTransactionScope scope(storage::DriverManager::getDatabase(DB_CERTIFICATE));
        std::shared_ptr<storage::SQLDatabase> connection = scope.database();
        storage::SQLQuery getCountQuery(connection->prepare(getCountString.str()));
        getCountQuery.exec();
        return getCountQuery.getInt(0);
    } catch (storage::StorageException& e) {
        BROWSER_LOGD("[%s:%d] SQLException (%d): %s ", __PRETTY_FUNCTION__, __LINE__, e.getErrorCode(), e.getMessage());
    }
    return 0;
}

unsigned int CertificateStorage::addOrUpdateCertificateEntry(const std::string& pem, const std::string& host, int allow)
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
    boost::format addCertificateQueryString("REPLACE INTO %1% ( %2%, %3%, %4% ) VALUES ( ?, ?, ? );");
    addCertificateQueryString % TABLE_CERTIFICATE % COL_HOST % COL_PEM % COL_ALLOW;
    try {
        storage::SQLTransactionScope scope(storage::DriverManager::getDatabase(DB_CERTIFICATE));
        std::shared_ptr<storage::SQLDatabase> db = scope.database();
        storage::SQLQuery addCertificateQuery(db->prepare(addCertificateQueryString.str()));
        addCertificateQuery.bindText(1, host);
        addCertificateQuery.bindText(2, pem);
        addCertificateQuery.bindInt(3, allow);
        addCertificateQuery.exec();
        return db->lastInsertId();
    } catch (storage::StorageException &e) {
        BROWSER_LOGD("[%s:%d] SQLException (%d): %s ", __PRETTY_FUNCTION__, __LINE__, e.getErrorCode(), e.getMessage());
    }
    return 0;
}

std::string CertificateStorage::getPemForURI(const std::string& uri)
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
    boost::format getPemString("SELECT %1% FROM %2% WHERE %3% = ?;");
    getPemString % COL_PEM % TABLE_CERTIFICATE % COL_HOST;
    try {
        storage::SQLTransactionScope scope(storage::DriverManager::getDatabase(DB_CERTIFICATE));
        std::shared_ptr<storage::SQLDatabase> connection = scope.database();
        storage::SQLQuery getPemQuery(connection->prepare(getPemString.str()));
        getPemQuery.bindText(1, uri);
        getPemQuery.exec();

        return getPemQuery.getString(0);
    } catch (storage::StorageException& e) {
        BROWSER_LOGD("[%s:%d] SQLException (%d): %s ", __PRETTY_FUNCTION__, __LINE__, e.getErrorCode(), e.getMessage());
    }
    return std::string();
}

void CertificateStorage::deleteAllEntries()
{
    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
    boost::format deleteCertificateString("DELETE FROM %1%;");
    deleteCertificateString % TABLE_CERTIFICATE;
    try {
        storage::SQLTransactionScope scope(storage::DriverManager::getDatabase(DB_CERTIFICATE));
        std::shared_ptr<storage::SQLDatabase> connection = scope.database();

        storage::SQLQuery deleteCertificatesQuery(connection->prepare(deleteCertificateString.str()));
        deleteCertificatesQuery.exec();
    } catch( storage::StorageException &e) {
        BROWSER_LOGD("[%s:%d] SQLException (%d): %s ", __PRETTY_FUNCTION__, __LINE__, e.getErrorCode(), e.getMessage());
    }
}

}//end namespace storage
}//end namespace tizen_browser

ext: cpp


text: #include <boost/intrusive/list_hook.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text: #include <boost/polygon/polygon_90_with_holes_data.hpp>


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

#include <stdio.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include <cmath>

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
#include <boost/concept_check.hpp>

#include "Antenna.h"
#include "Application.h"
#include "Debug.h"
#include "GPS.h"
#include "HexBin.h"
#include "Ublox.h"
#include "ReceiverMeasurement.h"
#include "SVMeasurement.h"

extern ostream *debugStream;
extern Application *app;

#define CLIGHT 299792458.0
#define ICD_PI 3.1415926535898

#define MAX_CHANNELS 16 // max channels per constellation
#define SLOPPINESS 0.1
#define CLOCKSTEP  0.001
#define MAX_GAP    3   // maximum permissible gap in observation sequence before ambiguity resolution is triggered
// types used by ublox receivers
typedef signed char    I1;
typedef unsigned char  U1;
typedef unsigned char  X1;
typedef unsigned short U2;
typedef short          I2;
typedef int            I4;
typedef unsigned int   U4;
typedef float          R4;
typedef double         R8;

// messages that are parsed
#define MSG0121 0x01
#define MSG0122 0x02
#define MSG0215 0x04
#define MSG0D01 0x08

Ublox::Ublox(Antenna *ant,string m):Receiver(ant)
{
	modelName=m;
	manufacturer="ublox";
	swversion="0.1";
	constellations=GNSSSystem::GPS;
	codes=GNSSSystem::C1;
	channels=32;
	if (modelName == "LEA8MT"){
		// For the future
	}
	else if (modelName == "NEO8MT"){
	}
	else{
		app->logMessage("Unknown receiver model: " + modelName);
		app->logMessage("Assuming NEO8MT");
	}
}

Ublox::~Ublox()
{
}

bool Ublox::readLog(string fname,int mjd,int startTime,int stopTime,int rinexObsInterval)
{
	DBGMSG(debugStream,INFO,"reading " << fname);

	ifstream infile (fname.c_str());
	string line;
	int linecount=0;

	string msgid,currpctime,pctime,msg,gpstime;

	I4 sawtooth;
	I4 clockBias;
	R8 measTOW;
	U2 measGPSWN;
	I1 measLeapSecs;

	U2 UTCyear;
	U1 UTCmon,UTCday,UTChour,UTCmin,UTCsec,UTCvalid;

	U1 u1buf;
	I2 i2buf;
	I4 i4buf;
	U4 u4buf;
	R4 r4buf;
	R8 r8buf;

	float rxTimeOffset; // single

	vector<SVMeasurement *> svmeas;

	gotUTCdata=false;
	gotIonoData=false;

	unsigned int currentMsgs=0;
	unsigned int reqdMsgs =  MSG0121 | MSG0122 | MSG0215 | MSG0D01 ;

  if (infile.is_open()){
    while ( getline (infile,line) ){
			linecount++;

			if (line.size()==0) continue; // skip empty line
			if ('#' == line.at(0)) continue; // skip comments
			if ('%' == line.at(0)) continue;
			if ('@' == line.at(0)) continue;

			stringstream sstr(line);
			sstr >> msgid >> currpctime >> msg;
			if (sstr.fail()){
				DBGMSG(debugStream,WARNING," bad data at line " << linecount);
				currentMsgs=0;
				deleteMeasurements(svmeas);
				continue;
			}

			// The 0x0215 message starts each second
			if(msgid == "0215"){ // raw measurements

				if (currentMsgs == reqdMsgs){ // save the measurements from the previous second
					if (svmeas.size() > 0){
						ReceiverMeasurement *rmeas = new ReceiverMeasurement();
						measurements.push_back(rmeas);

						rmeas->sawtooth=sawtooth*1.0E-12; // units are ps, must be added to TIC measurement
						rmeas->timeOffset=clockBias*1.0E-9; // units are ns WARNING no sign convention defined yet ...

						int pchh,pcmm,pcss;
						if ((3==sscanf(pctime.c_str(),"%d:%d:%d",&pchh,&pcmm,&pcss))){
							rmeas->pchh=pchh;
							rmeas->pcmm=pcmm;
							rmeas->pcss=pcss;
						}

						// GPSTOW is used for pseudorange estimations
						// note: this is rounded because measurements are interpolated on a 1s grid
						rmeas->gpstow=rint(measTOW);
						rmeas->gpswn=measGPSWN % 1024; // Converted to truncated WN. Not currently used

						// UTC time of measurement
						// We could use other time information to calculate this eg gpstow,gpswn and leap seconds
						rmeas->tmUTC.tm_sec=UTCsec;
						rmeas->tmUTC.tm_min=UTCmin;
						rmeas->tmUTC.tm_hour=UTChour;
						rmeas->tmUTC.tm_mday=UTCday;
						rmeas->tmUTC.tm_mon=UTCmon-1;
						rmeas->tmUTC.tm_year=UTCyear-1900;
						rmeas->tmUTC.tm_isdst=0;

						// Calculate GPS time of measurement
						// FIXME why do this ? why not just convert from UTC ? and full WN is known anyway
						time_t tgps = GPS::GPStoUnix(rmeas->gpstow,rmeas->gpswn);
						struct tm *tmGPS = gmtime(&tgps);
						rmeas->tmGPS=*tmGPS;

						//rmeas->tmfracs = measTOW - (int)(measTOW);
						//if (rmeas->tmfracs > 0.5) rmeas->tmfracs -= 1.0; // place in the previous second

						rmeas->tmfracs=0.0;

						if (constellations & GNSSSystem::GPS){
							for (unsigned int sv=0;sv<svmeas.size();sv++){
								svmeas.at(sv)->dbuf3 = svmeas.at(sv)->meas; // save for debugging
								svmeas.at(sv)->meas -= clockBias*1.0E-9; // evidently it is subtracted
								// Now subtract the ms part so that ms ambiguity resolution works
								svmeas.at(sv)->meas -= 1.0E-3*floor(svmeas.at(sv)->meas/1.0E-3);
								svmeas.at(sv)->rm=rmeas;
							}
							rmeas->meas=svmeas;
							svmeas.clear(); // don't delete - we only made a shallow copy!
						}

						// KEEP THIS it's useful for debugging measurement-time related problems
					//fprintf(stderr,"PC=%02d:%02d:%02d tmUTC=%02d:%02d:%02d tmGPS=%4d %02d:%02d:%02d gpstow=%d gpswn=%d measTOW=%.12lf tmfracs=%g clockbias=%g\n",
					//	pchh,pcmm,pcss,UTChour,UTCmin,UTCsec, rmeas->tmGPS.tm_year+1900,rmeas->tmGPS.tm_hour, rmeas->tmGPS.tm_min,rmeas->tmGPS.tm_sec,
					//	(int) rmeas->gpstow,(int) rmeas->gpswn,measTOW,rmeas->tmfracs,clockBias*1.0E-9  );

					//fprintf(stderr,"%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %d %d %.12lf %g %g\n",
					//pchh,pcmm,pcss,UTChour,UTCmin,UTCsec, rmeas->tmGPS.tm_hour, rmeas->tmGPS.tm_min,rmeas->tmGPS.tm_sec,
					//(int) rmeas->gpstow,(int) rmeas->gpswn,measTOW,rmeas->tmfracs,clockBias*1.0E-9  );

					}// if (gpsmeas.size() > 0)
				}
				else{
					DBGMSG(debugStream,TRACE,pctime << " reqd message missing, flags = " << currentMsgs);
					deleteMeasurements(svmeas);
				}

				pctime=currpctime;
				currentMsgs = 0;

				if (msg.size()-2*2-16*2 > 0){ // don't know the expected message size yet but if we've got the header ...
					HexToBin((char *) msg.substr(11*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &u1buf);
					unsigned int nmeas=u1buf;
					if (msg.size() == (2+16+nmeas*32)*2){
						HexToBin((char *) msg.substr(0*2,2*sizeof(R8)).c_str(),sizeof(R8),(unsigned char *) &measTOW); //measurement TOW (s)
						HexToBin((char *) msg.substr(8*2,2*sizeof(U2)).c_str(),sizeof(U2),(unsigned char *) &measGPSWN); // full WN
						HexToBin((char *) msg.substr(10*2,2*sizeof(I1)).c_str(),sizeof(I1),(unsigned char *) &measLeapSecs);
						DBGMSG(debugStream,TRACE,currpctime << " meas tow=" << measTOW << setprecision(12) << " gps wn=" << (int) measGPSWN << " leap=" << (int) measLeapSecs);
						//DBGMSG(debugStream,TRACE,nmeas);
						for (unsigned int m=0;m<nmeas;m++){
							HexToBin((char *) msg.substr((36+32*m)*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &u1buf); //GNSS id
							int gnssSys = 0;
							switch (u1buf){
								case 0: gnssSys=GNSSSystem::GPS; break;
								case 1:case 4: case 5: break;
								case 2: gnssSys=GNSSSystem::GALILEO; break;
								case 3: gnssSys=GNSSSystem::BEIDOU; break;
								case 6: gnssSys=GNSSSystem::GLONASS; break;
								default: break;
							}
							//DBGMSG(debugStream,TRACE,gnssSys);
							if (gnssSys & constellations ){
								// Since we get all the measurements in one message (which starts each second) there's no need to check for multiple measurement messages
								// like with eg the Resolution T
								HexToBin((char *) msg.substr((16+32*m)*2,2*sizeof(R8)).c_str(),sizeof(R8),(unsigned char *) &r8buf); //pseudorange (m)
								HexToBin((char *) msg.substr((37+32*m)*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &u1buf); //svid
								int svID=u1buf;
								HexToBin((char *) msg.substr((46+32*m)*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &u1buf);
								int prStdDev= u1buf & 0x0f;
								HexToBin((char *) msg.substr((46+32*m)*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &u1buf);
								int trkStat=u1buf;
								// When PR is reported, trkStat is always 1 but .
								if (trkStat > 0 && r8buf/CLIGHT < 1.0){
									SVMeasurement *svm = new SVMeasurement(svID,gnssSys,GNSSSystem::C1,r8buf/CLIGHT,NULL);
									//svm->dbuf1=0.01*pow(2.0,prStdDev);
									svmeas.push_back(svm);
								}
								DBGMSG(debugStream,TRACE,"SYS " <<gnssSys << " SV" << svID << " pr=" << r8buf/CLIGHT << setprecision(8) << " trkStat= " << (int) trkStat);
							}
						}
						currentMsgs |= MSG0215;
					}
					else{
						DBGMSG(debugStream,WARNING,"Bad 0215 message size");
					}
				}
				else{
					DBGMSG(debugStream,WARNING,"empty/malformed 0215 message");
				}

				continue;

			} // raw measurements

			// 0x0D01 Timepulse time data (sawtooth correction)
			if(msgid == "0d01"){

				if (msg.size()==(16+2)*2){
					X1 TPflags,TPrefInfo;
					U4 TPTOW;
					HexToBin((char *) msg.substr(0*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &TPTOW); // (ms)
					HexToBin((char *) msg.substr(8*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &sawtooth); // (ps)
					HexToBin((char *) msg.substr(14*2,2*sizeof(X1)).c_str(),sizeof(X1),(unsigned char *) &TPflags);
					HexToBin((char *) msg.substr(15*2,2*sizeof(X1)).c_str(),sizeof(X1),(unsigned char *) &TPrefInfo);
					DBGMSG(debugStream,TRACE,currpctime << " tow= " << (int) TPTOW << " sawtooth=" << sawtooth << " ps" << std::hex << " flags=0x" << (unsigned int) TPflags <<
						" ref=0x" << (unsigned int) TPrefInfo << std::dec);
					currentMsgs |= MSG0D01;
				}
				else{
					DBGMSG(debugStream,WARNING,"Bad 0d01 message size");
				}
			}
			// 0x0135 UBX-NAV-SAT satellite information

			// 0x0121 UBX-NAV-TIME-UTC UTC time solution
			if(msgid == "0121"){
				if (msg.size()==(20+2)*2){
					HexToBin((char *) msg.substr(12*2,2*sizeof(U2)).c_str(),sizeof(U2),(unsigned char *) &UTCyear);
					HexToBin((char *) msg.substr(14*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &UTCmon);
					HexToBin((char *) msg.substr(15*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &UTCday);
					HexToBin((char *) msg.substr(16*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &UTChour);
					HexToBin((char *) msg.substr(17*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &UTCmin);
					HexToBin((char *) msg.substr(18*2,2*sizeof(U1)).c_str(),sizeof(U1),(unsigned char *) &UTCsec);
					HexToBin((char *) msg.substr(19*2,2*sizeof(X1)).c_str(),sizeof(X1),(unsigned char *) &UTCvalid);
					DBGMSG(debugStream,TRACE,currpctime << " UTC:" << UTCyear << " " << (int) UTCmon << " " << (int) UTCday << " "
						<< (int) UTChour << ":" << (int) UTCmin << ":" << (int) UTCsec << " valid=" << (unsigned int) UTCvalid);
					if (UTCvalid & 0x04)
						currentMsgs |= MSG0121;
					else{
						DBGMSG(debugStream,WARNING,"UTC not valid yet");
					}
				}
				else{
					DBGMSG(debugStream,WARNING,"Bad 0121 message size");
				}
				continue;
			}

			// 0x0122 UBX-NAV-CLOCK clock solution  (clock bias)
			if(msgid == "0122"){
				if (msg.size()==(20+2)*2){
						HexToBin((char *) msg.substr(0*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf); // GPS tow of navigation epoch (ms)
						HexToBin((char *) msg.substr(4*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &clockBias); // in ns

						DBGMSG(debugStream,TRACE,"GPS tow=" << u4buf << "ms" << " clock bias=" << clockBias << " ns");
						currentMsgs |= MSG0122;
				}
				else{
					DBGMSG(debugStream,WARNING,"Bad 0122 message size");
				}
				continue;
			}

			//
			// Messages needed to contruct the RINEX navigation file
			//

			// Ionosphere parameters, UTC parameters
			if (!gotUTCdata){
				if(msgid == "0b02"){
					if (msg.size()==(72+2)*2){
						HexToBin((char *) msg.substr(4*2,2*sizeof(R8)).c_str(),sizeof(R8),(unsigned char *) &(gps.UTCdata.A0));
						HexToBin((char *) msg.substr(12*2,2*sizeof(R8)).c_str(),sizeof(R8),(unsigned char *) &r8buf);
						gps.UTCdata.A1=r8buf;
						HexToBin((char *) msg.substr(20*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &i4buf);
						gps.UTCdata.t_ot = i4buf;
						HexToBin((char *) msg.substr(24*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &i2buf);
						gps.UTCdata.WN_t=i2buf;
						HexToBin((char *) msg.substr(26*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &i2buf);
						leapsecs = i2buf;
						HexToBin((char *) msg.substr(28*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &i2buf);
						gps.UTCdata.WN_LSF=i2buf;
						HexToBin((char *) msg.substr(30*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &i2buf);
						gps.UTCdata.DN=i2buf;
						HexToBin((char *) msg.substr(32*2,2*sizeof(I4)).c_str(),sizeof(I4),(unsigned char *) &i2buf);
						gps.UTCdata.dt_LSF=i2buf;

						HexToBin((char *) msg.substr(36*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.a0));
						HexToBin((char *) msg.substr(40*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.a1));
						//gps.ionoData.a1 /= ICD_PI;
						HexToBin((char *) msg.substr(44*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.a2));
						//gps.ionoData.a2 /= (ICD_PI*ICD_PI);
						HexToBin((char *) msg.substr(48*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.a3));
						//gps.ionoData.a3 /= (ICD_PI*ICD_PI*ICD_PI);

						HexToBin((char *) msg.substr(52*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.B0));
						HexToBin((char *) msg.substr(56*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.B1));
						//gps.ionoData.B1 /= ICD_PI;
						HexToBin((char *) msg.substr(60*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.B2));
						//gps.ionoData.B2 /= (ICD_PI*ICD_PI);
						HexToBin((char *) msg.substr(64*2,2*sizeof(R4)).c_str(),sizeof(R4),(unsigned char *) &(gps.ionoData.B3));
						//gps.ionoData.B3 /= (ICD_PI*ICD_PI*ICD_PI);

						gotUTCdata=true;
						gotIonoData=true;
					}
					else{
						DBGMSG(debugStream,WARNING,"Bad 0b02 message size");
					}
					continue;
				}
			}

			// Ephemeris
			if(msgid == "0b31"){
				if (msg.size()==(8+2)*2){
					DBGMSG(debugStream,WARNING,"Empty ephemeris");
				}
				else if (msg.size()==(104+2)*2){
					GPS::EphemerisData *ed = decodeGPSEphemeris(msg);
					int pchh,pcmm,pcss;
						if ((3==sscanf(pctime.c_str(),"%d:%d:%d",&pchh,&pcmm,&pcss)))
							ed->tLogged = pchh*3600 + pcmm*60 + pcss;
						else
							ed->tLogged = -1;
					gps.addEphemeris(ed);
				}
				else{
					DBGMSG(debugStream,WARNING,"Bad 0b31 message size");
				}
				continue;
			} // ephemeris
		}
	} // infile is open
	else{
		app->logMessage(" unable to open " + fname);
		return false;
	}
	infile.close();

	if (!gotUTCdata){
		app->logMessage("failed to find ionosphere/UTC parameters - no 0b02 messages");
		//return false; // FIXME temporary
	}

	if (measurements.size() == 0){
		app->logMessage(" no measurements available in " + fname);
		return false;
	}

	// Pass through the data to realign the sawtooth correction.
	// This could be done in the main loop but it's more flexible this way.
	// For the ublox, the sawtooth correction applies to the next second
	// If we're missing the sawtooth correction because of eg a gap in the data
	// then we'll just use the current sawtooth.

	DBGMSG(debugStream,TRACE,"Fixing sawtooth");
	double prevSawtooth=measurements.at(0)->sawtooth;
	time_t    tPrevSawtooth=mktime(&(measurements.at(0)->tmUTC));
	int nBadSawtoothCorrections =1; // first is bad !
	// First point is untouched
	for (unsigned int i=1;i<measurements.size();i++){
		double sawTmp = measurements.at(i)->sawtooth;
		time_t tTmp= mktime(&(measurements.at(i)->tmUTC));
		if (tTmp - tPrevSawtooth == 1){
			measurements.at(i)->sawtooth = prevSawtooth;
		}
		else{
			// do nothing - the current value is the best guess
			nBadSawtoothCorrections++;
		}
		prevSawtooth=sawTmp;
		tPrevSawtooth=tTmp;
	}

	// The Ublox sometime reports what appears to be an incorrect pseudorange after picking up an SV
	// If you wanted to filter these out, this is where you should do it

	// Fix 1 ms ambiguities/steps in the pseudorange
	// Do this initially and then every time a step is detected

	DBGMSG(debugStream,TRACE,"Fixing ms ambiguities");
	int nDropped;
	for (int g=GNSSSystem::GPS;g<=GNSSSystem::GALILEO;(g <<= 1)){
		if (!(g & constellations)) continue;
		GNSSSystem *gnss;
		switch (g){
			case GNSSSystem::BEIDOU:gnss=&beidou;break;
			case GNSSSystem::GALILEO:gnss=&galileo;break;
			case GNSSSystem::GLONASS:gnss=&glonass;break;
			case GNSSSystem::GPS:gnss=&gps;break;
			default:break;
		}
		for (int svn=1;svn<=gnss->nsats();svn++){
			unsigned int lasttow=99999999,currtow=99999999;
			double lastmeas=0,currmeas;
			double corr=0.0;
			bool first=true;
			bool ok=false;
			for (unsigned int i=0;i<measurements.size();i++){
				unsigned int m=0;
				while (m < measurements[i]->meas.size()){
					if ((svn==measurements[i]->meas[m]->svn) && (measurements[i]->meas[m]->code == GNSSSystem::C1)){
						lasttow=currtow;
						lastmeas=currmeas;
						currmeas=measurements[i]->meas[m]->meas;
						currtow=measurements[i]->gpstow;

						DBGMSG(debugStream,TRACE,svn << " " << currtow << " " << currmeas << " ");
						if (first){
							ok = gnss->resolveMsAmbiguity(antenna,measurements[i],measurements[i]->meas[m],&corr);
							if (ok){
								first=false;
							}
						}
						else if (currtow - lasttow > MAX_GAP){
							DBGMSG(debugStream,TRACE,"gap " << svn << " " << lasttow << "," << lastmeas << "->" << currtow << "," << currmeas);
							ok = gnss->resolveMsAmbiguity(antenna,measurements[i],measurements[i]->meas[m],&corr);
						}
						else if (currtow > lasttow){
							if (fabs(currmeas-lastmeas) > CLOCKSTEP*SLOPPINESS){
								DBGMSG(debugStream,TRACE,"first/step " << svn << " " << lasttow << "," << lastmeas << "->" << currtow << "," << currmeas);
								ok = gnss->resolveMsAmbiguity(antenna,measurements[i],measurements[i]->meas[m],&corr);
							}
						}
						if (ok){
							measurements[i]->meas[m]->meas += corr;
							m++;
						}
						else{ // ambiguity correction failed, so drop the measurement
							nDropped++;
							measurements[i]->meas.erase(measurements[i]->meas.begin()+m); // FIXME memory leak
						}
						break;
					}
					else
						m++;

				} //
			} // for (unsigned int i=0;i<measurements.size();i++){
		}
	}

	DBGMSG(debugStream,INFO,"done: read " << linecount << " lines");
	DBGMSG(debugStream,INFO,measurements.size() << " measurements read");
	DBGMSG(debugStream,INFO,gps.ephemeris.size() << " GPS ephemeris entries read");
	DBGMSG(debugStream,INFO,nBadSawtoothCorrections << " bad sawtooth corrections");
	DBGMSG(debugStream,INFO,"dropped " << nDropped << " SV measurements (ms ambiguity failure)");

	return true;

}

GPS::EphemerisData* Ublox::decodeGPSEphemeris(string msg)
{
	U4 u4buf;
	HexToBin((char *) msg.substr(0*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	GPS::EphemerisData* ed= new GPS::EphemerisData();
	ed->SVN=u4buf;
	DBGMSG(debugStream,TRACE,"Ephemeris for SV" << (int) ed->SVN);

	// cerr << "EPH" << endl;

	// To use the MID macro, LSB is bit 0, m is first bit, n is last bit
	#define LAST(k,n) ((k) & ((1<<(n))-1))
	#define MID(k,m,n) LAST((k)>>(m),((n)-(m)+1))

	// Data is in bits 0-23, parity bits are discarded by ublox
	// To translate from ICD numbering b24 (ICD) -> b0 (ublox)
	// subframe 1
	// word 3
	HexToBin((char *) msg.substr(8*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);

	ed->week_number = MID(u4buf,14,23);
	ed->SV_accuracy_raw=MID(u4buf,8,11);
	ed->SV_accuracy = GPS::URA[ed->SV_accuracy_raw];
	ed->SV_health=MID(u4buf,2,7);
	// IODC b23-b24 (upper bits)
	unsigned int hibits=MID(u4buf,0,1);
	hibits = hibits << 8;

	//fprintf(stderr,"%i %08x %i %i %i\n",(int) ed->SVN,u4buf, (int) ed->week_number,
	//	(int) ed->SV_accuracy, ed->SV_health);

	// word 7
	HexToBin((char *) msg.substr(24*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	//Tgd b17-b24 (ICD) CHECKED
	signed char tGD = MID(u4buf,0,7); // signed, scaled by 2^-31
	ed->t_GD =  (double) tGD / (double) pow(2,31);

	//fprintf(stderr,"%08x %.12e\n",u4buf,ed->t_GD);

	// word 8
	HexToBin((char *) msg.substr(28*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	// IODC b1-b8 (lower bits) // CHECKED
	unsigned int lobits = MID(u4buf,16,23);
	ed->IODC = hibits | lobits;
	// t_OC b9-b24 (ICD)
	ed->t_OC = 16*MID(u4buf,0,15);
	//fprintf(stderr,"%08x %e %i\n",u4buf,ed->t_OC,(int) ed->IODC);

	// word 9 a_f2 b1-b8, a_f1 b9-b24 // CHECKED a_f1
	HexToBin((char *) msg.substr(32*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed char af2 = MID(u4buf,16,23);
	ed->a_f2 = af2/pow(2,55);
	signed short af1= MID(u4buf,0,15);
	ed->a_f1 = (double) af1/(double) pow(2,43);

	//fprintf(stderr,"%08x %.12e %.12e\n",u4buf,ed->a_f1,ed->a_f2);
	if (ed->a_f2 != 0.0) fprintf(stderr,"BING!\n");

	// word 10 a_f0 b1-b22 // CHECKED
	HexToBin((char *) msg.substr(36*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	int tmp = (MID(u4buf,2,23) << 10);
	tmp = tmp >> 10;
	ed->a_f0 = (double) tmp /(double) pow(2,31); // signed, scaled by 2^-31
	//fprintf(stderr,"%08x %.12e\n",u4buf,ed->a_f0);

	// data frame 2
	// word 3
	// IODE b1-b8 // CHECKED
	HexToBin((char *) msg.substr(40*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	ed->IODE = MID(u4buf,16,23);
	// C_rs b9-b24 // CHECKED
	signed short Crs= MID(u4buf,0,15);
	ed->C_rs= (double) Crs/ (double) 32.0;
	//fprintf(stderr,"%08x %i %.12e\n",u4buf,ed->IODE,ed->C_rs);

	// word 4
	// deltaN b1-b16 // CHECKED nb this is a SINGLE so differences in 7 or 8th digit in RINEX files
	HexToBin((char *) msg.substr(44*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed short deltaN=MID(u4buf,8,23);
	ed->delta_N = ICD_PI*(double) deltaN/(double) pow(2,43); // GPS units are semi-circles/s, RINEX units are rad/s
	// M_0 (upper 8 bits) b17-b24
	hibits =  MID(u4buf,0,7) << 24;

	// word 5
	// M_0 (lower 24 bits) b1-b24 // CHECKED
	HexToBin((char *) msg.substr(48*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	lobits = MID(u4buf,0,23);

	ed->M_0 = ICD_PI * ((double) ((int) (hibits | lobits)))/ (double) pow(2,31);
	//fprintf(stderr,"%08x %.12e %.12e\n",u4buf,ed->delta_N, ed->M_0);

	// word 6
	// C_uc b1-b16 // CHECKED
	HexToBin((char *) msg.substr(52*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed short Cuc=MID(u4buf,8,23);
	ed->C_uc = (double) Cuc/(double) pow(2,29);
	// e b17-b24 (upper 8 bits)
	hibits =  MID(u4buf,0,7) << 24;

	// word 7
	// e b1-b24 (lower 24 bits) // CHECKED
	HexToBin((char *) msg.substr(56*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	lobits = MID(u4buf,0,23);
	ed->e = ((double) (unsigned int)((hibits | lobits)))/ (double) pow(2,33);
	//fprintf(stderr,"%08x %.12e %.12e \n",u4buf,ed->C_uc,ed->e);

	// word 8
	// C_us b1-b16 // CHECKED
	HexToBin((char *) msg.substr(60*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed short Cus=MID(u4buf,8,23);
	ed->C_us = (double) Cus/(double) pow(2,29);
	// sqrtA b1-b8 (upper bits)
	hibits =  MID(u4buf,0,7) << 24;

	// word 9
	//sqrtA b1-b24 (lower bits) // CHECKED
	HexToBin((char *) msg.substr(64*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	lobits = MID(u4buf,0,23);
	ed->sqrtA = ((double) (unsigned int)((hibits | lobits)))/ (double) pow(2,19);
	//fprintf(stderr,"%08x %.12e %.12e\n",u4buf,ed->C_us,ed->sqrtA);

	// word 10
	// t_OE b1-b16 // CHECKED
	HexToBin((char *) msg.substr(68*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	unsigned short toe=MID(u4buf,8,23);
	ed->t_oe = toe * 16;
	//fprintf(stderr,"%08x %.12e \n",u4buf,ed->t_oe);

	// data frame 3
	// word 3
	// C_ic b1-b16 // CHECKED
	HexToBin((char *) msg.substr(72*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed short Cic=MID(u4buf,8,23);
	ed->C_ic = (double) Cic/(double) pow(2,29);
	// OMEGA_0 b17-b24 (upper bits)
	hibits =  MID(u4buf,0,7) << 24;

	// word 4
	// OMEGA_0 b1-b24 lower bits // CHECKED
	HexToBin((char *) msg.substr(76*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	lobits = MID(u4buf,0,23);
	ed->OMEGA_0 = ICD_PI * ((double) (signed int)((hibits | lobits)))/ (double) pow(2,31);
	//fprintf(stderr,"%08x %.12e %.12e\n",u4buf,ed->C_ic,ed->OMEGA_0);

	// word 5
	// C_is b1-b16 // CHECKED
	HexToBin((char *) msg.substr(80*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed short Cis=MID(u4buf,8,23);
	ed->C_is= (double) Cis/(double) pow(2,29);
	// i_0 b17-b24 (upper bits)
	hibits =  MID(u4buf,0,7) << 24;

	// word 6
	// i_0 b1-b24 (lower bits) // CHECKED
	HexToBin((char *) msg.substr(84*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	lobits = MID(u4buf,0,23);
	ed->i_0 = ICD_PI * ((double) (signed int)((hibits | lobits)))/ (double) pow(2,31);
	//fprintf(stderr,"%08x %.12e %.12e\n",u4buf,ed->C_is,ed->i_0);

	// word 7
	// C_rc b1-b16 // CHECKED
	HexToBin((char *) msg.substr(88*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	signed short Crc=MID(u4buf,8,23);
	ed->C_rc= (double) Crc/32.0;
	// OMEGA b17-b24 (upper bits)
	hibits =  MID(u4buf,0,7) << 24;

	// word 8
	// OMEGA b1-b24 (lower bits) // CHECKED
	HexToBin((char *) msg.substr(92*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	lobits = MID(u4buf,0,23);
	ed->OMEGA = ICD_PI * ((double) (signed int)((hibits | lobits)))/ (double) pow(2,31);
	//fprintf(stderr,"%08x %.12e %.12e\n",u4buf,ed->C_rc,ed->OMEGA);

	// word 9
	// OMEGA_DOT b1-b24 // CHECKED
	HexToBin((char *) msg.substr(96*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	int odot = (MID(u4buf,0,23)) << 8;
	odot = odot >> 8;
	ed->OMEGADOT = ICD_PI * (double) (odot)/ (double) pow(2,43);
	//fprintf(stderr,"%08x %.12e\n",u4buf,ed->OMEGADOT);

	// word 10
	// IODE b1-b8 (repeated to facilitate checking for data cutovers) ... but which one should I use ???
	// IDOT b9-b22 // CHECKED
	HexToBin((char *) msg.substr(100*2,2*sizeof(U4)).c_str(),sizeof(U4),(unsigned char *) &u4buf);
	int idot = (MID(u4buf,2,15)) << 18;
	idot = idot >> 18;
	ed->IDOT = ICD_PI * (double) (idot)/ (double) pow(2,43);
	//fprintf(stderr,"%08x %.12e\n",u4buf,ed->IDOT);

	return ed;
}

max_stars_repo_name: openttp/openttp

max_issues_repo_name: openttp/openttp

max_forks_repo_name: openttp/openttp


text:
#ifndef ILP_DIGRAPH_HPP
#define ILP_DIGRAPH_HPP

#include "ilp_task.hpp"

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/adj_list_serialize.hpp>

#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <utility>
#include <functional>

namespace ilp
{
    //////////////////////////
    //   BASE GRAPH TYPES   //
    //////////////////////////

    using VerticesStorageType = boost::vecS;
    using EdgesStorageType    = boost::vecS;
    using DirectedCategory    = boost::directedS;

    using BaseGraphTraits = boost::adjacency_list_traits<
              VerticesStorageType
            , EdgesStorageType
            , DirectedCategory
            >;

    using VertexDescriptor = BaseGraphTraits::vertex_descriptor;
    using EdgeDescriptor   = BaseGraphTraits::edge_descriptor;

    struct VertexProperty
    {
        cvector<int> point;
        VertexDescriptor predecessor = { };
        int distance = std::numeric_limits<int>::max();
    };

    struct EdgeProperty
    {
        int weight;
        int column;
    };

    using BaseGraph = boost::adjacency_list<
              VerticesStorageType
            , EdgesStorageType
            , DirectedCategory
            , VertexProperty
            , EdgeProperty
            >;

    ///////////////////////
    //   ADAPTOR GRAPH   //
    ///////////////////////

    struct DigraphAdaptor
    {
    public:
        explicit DigraphAdaptor(const ilp::ilp_task& ilpTask);

        template <typename VertexPoint>
        std::pair<VertexDescriptor, bool> add_vertex(VertexPoint&& point)
        {
            auto it = m_points_set.find(point);
            if (it != m_points_set.end())
            {
                return {it->second, false};
            }

            auto vertex_descriptor = boost::add_vertex(VertexProperty{}, m_base);
            auto [new_it, is_inserted] = m_points_set.emplace(
                    std::make_pair(std::forward<VertexPoint>(point), vertex_descriptor)
            );
            m_base[vertex_descriptor].point = new_it->first;

            return {vertex_descriptor, true};
        }

        template <typename EdgePropertyType>
        std::pair<EdgeDescriptor, bool> add_edge(VertexDescriptor lhs,
                                                 VertexDescriptor rhs,
                                                 EdgePropertyType&& property
        )
        {
            return boost::add_edge(lhs, rhs, std::forward<EdgePropertyType>(property), m_base);
        }

        bool is_feasible() const noexcept;

    public:
        const ilp::ilp_task& ilpTask;

        BaseGraph m_base;
        std::unordered_map<cvector<int>, VertexDescriptor, detail::VectorHash<int>> m_points_set;

        VertexDescriptor start;
        VertexDescriptor end;
        bool bIsFeasible;

    private:
        virtual bool populate_condition(const cvector<int>& b,
                                        const cvector<int>& p,
                                        int bound) const = 0;

        virtual void populate_from(VertexDescriptor vertex,
                                   int bound) = 0;

        virtual void populate_graph() = 0;
    };

} // namespace ilp

#endif // ILP_DIGRAPH_HPP