mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Library libdevcore renamed to libsolutil.
This commit is contained in:
committed by
Daniel Kirchner
parent
8ac6258d31
commit
345f9928ab
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <set>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/**
|
||||
* Detector for cycles in directed graphs. It returns the first
|
||||
* vertex on the path towards a cycle or a nullptr if there is
|
||||
* no reachable cycle starting from a given vertex.
|
||||
*/
|
||||
template <typename V>
|
||||
class CycleDetector
|
||||
{
|
||||
public:
|
||||
using Visitor = std::function<void(V const&, CycleDetector&, size_t)>;
|
||||
|
||||
/// Initializes the cycle detector
|
||||
/// @param _visit function that is given the current vertex
|
||||
/// and is supposed to call @a run on all
|
||||
/// adjacent vertices.
|
||||
explicit CycleDetector(Visitor _visit):
|
||||
m_visit(std::move(_visit))
|
||||
{ }
|
||||
|
||||
/// Recursively perform cycle detection starting
|
||||
/// (or continuing) with @param _vertex
|
||||
/// @returns the first vertex on the path towards a cycle from @a _vertex
|
||||
/// or nullptr if no cycle is reachable from @a _vertex.
|
||||
V const* run(V const& _vertex)
|
||||
{
|
||||
if (m_firstCycleVertex)
|
||||
return m_firstCycleVertex;
|
||||
if (m_processed.count(&_vertex))
|
||||
return nullptr;
|
||||
else if (m_processing.count(&_vertex))
|
||||
return m_firstCycleVertex = &_vertex;
|
||||
m_processing.insert(&_vertex);
|
||||
|
||||
m_depth++;
|
||||
m_visit(_vertex, *this, m_depth);
|
||||
m_depth--;
|
||||
if (m_firstCycleVertex && m_depth == 1)
|
||||
m_firstCycleVertex = &_vertex;
|
||||
|
||||
m_processing.erase(&_vertex);
|
||||
m_processed.insert(&_vertex);
|
||||
return m_firstCycleVertex;
|
||||
}
|
||||
|
||||
private:
|
||||
Visitor m_visit;
|
||||
std::set<V const*> m_processing;
|
||||
std::set<V const*> m_processed;
|
||||
size_t m_depth = 0;
|
||||
V const* m_firstCycleVertex = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic breadth first search.
|
||||
*
|
||||
* Note that V needs to be a comparable value type. If it is not, use a pointer type,
|
||||
* but note that this might lead to non-deterministic traversal.
|
||||
*
|
||||
* Example: Gather all (recursive) children in a graph starting at (and including) ``root``:
|
||||
*
|
||||
* Node const* root = ...;
|
||||
* std::set<Node const*> allNodes = BreadthFirstSearch<Node const*>{{root}}.run([](Node const* _node, auto&& _addChild) {
|
||||
* // Potentially process ``_node``.
|
||||
* for (Node const& _child: _node->children())
|
||||
* // Potentially filter the children to be visited.
|
||||
* _addChild(&_child);
|
||||
* }).visited;
|
||||
*/
|
||||
template<typename V>
|
||||
struct BreadthFirstSearch
|
||||
{
|
||||
/// Runs the breadth first search. The verticesToTraverse member of the struct needs to be initialized.
|
||||
/// @param _forEachChild is a callable of the form [...](V const& _node, auto&& _addChild) { ... }
|
||||
/// that is called for each visited node and is supposed to call _addChild(childNode) for every child
|
||||
/// node of _node.
|
||||
template<typename ForEachChild>
|
||||
BreadthFirstSearch& run(ForEachChild&& _forEachChild)
|
||||
{
|
||||
while (!verticesToTraverse.empty())
|
||||
{
|
||||
V v = *verticesToTraverse.begin();
|
||||
verticesToTraverse.erase(verticesToTraverse.begin());
|
||||
visited.insert(v);
|
||||
|
||||
_forEachChild(v, [this](V _vertex) {
|
||||
if (!visited.count(_vertex))
|
||||
verticesToTraverse.emplace(std::move(_vertex));
|
||||
});
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::set<V> verticesToTraverse;
|
||||
std::set<V> visited{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
namespace formatting
|
||||
{
|
||||
|
||||
// control codes
|
||||
static constexpr char const* RESET = "\033[0m";
|
||||
static constexpr char const* INVERSE = "\033[7m";
|
||||
static constexpr char const* BOLD = "\033[1m";
|
||||
static constexpr char const* BRIGHT = BOLD;
|
||||
|
||||
// standard foreground colors
|
||||
static constexpr char const* BLACK = "\033[30m";
|
||||
static constexpr char const* RED = "\033[31m";
|
||||
static constexpr char const* GREEN = "\033[32m";
|
||||
static constexpr char const* YELLOW = "\033[33m";
|
||||
static constexpr char const* BLUE = "\033[34m";
|
||||
static constexpr char const* MAGENTA = "\033[35m";
|
||||
static constexpr char const* CYAN = "\033[36m";
|
||||
static constexpr char const* WHITE = "\033[37m";
|
||||
|
||||
// standard background colors
|
||||
static constexpr char const* BLACK_BACKGROUND = "\033[40m";
|
||||
static constexpr char const* RED_BACKGROUND = "\033[41m";
|
||||
static constexpr char const* GREEN_BACKGROUND = "\033[42m";
|
||||
static constexpr char const* YELLOW_BACKGROUND = "\033[43m";
|
||||
static constexpr char const* BLUE_BACKGROUND = "\033[44m";
|
||||
static constexpr char const* MAGENTA_BACKGROUND = "\033[45m";
|
||||
static constexpr char const* CYAN_BACKGROUND = "\033[46m";
|
||||
static constexpr char const* WHITE_BACKGROUND = "\033[47m";
|
||||
|
||||
// 256-bit-colors (incomplete set)
|
||||
static constexpr char const* RED_BACKGROUND_256 = "\033[48;5;160m";
|
||||
static constexpr char const* ORANGE_BACKGROUND_256 = "\033[48;5;166m";
|
||||
|
||||
}
|
||||
|
||||
/// AnsiColorized provides a convenience helper to colorize ostream with formatting-reset assured.
|
||||
class AnsiColorized
|
||||
{
|
||||
public:
|
||||
AnsiColorized(std::ostream& _os, bool const _enabled, std::vector<char const*>&& _formatting):
|
||||
m_stream{_os}, m_enabled{_enabled}, m_codes{std::move(_formatting)}
|
||||
{
|
||||
if (m_enabled)
|
||||
for (auto const& code: m_codes)
|
||||
m_stream << code;
|
||||
}
|
||||
|
||||
~AnsiColorized()
|
||||
{
|
||||
if (m_enabled)
|
||||
m_stream << formatting::RESET;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(T&& _t)
|
||||
{
|
||||
return m_stream << std::forward<T>(_t);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& m_stream;
|
||||
bool m_enabled;
|
||||
std::vector<char const*> m_codes;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file Assertions.h
|
||||
* @author Christian <c@ethdev.com>
|
||||
* @date 2015
|
||||
*
|
||||
* Assertion handling.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define ETH_FUNC __FUNCSIG__
|
||||
#elif defined(__GNUC__)
|
||||
#define ETH_FUNC __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define ETH_FUNC __func__
|
||||
#endif
|
||||
|
||||
/// Assertion that throws an exception containing the given description if it is not met.
|
||||
/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong.");
|
||||
/// Do NOT supply an exception object as the second parameter.
|
||||
#define assertThrow(_condition, _ExceptionType, _description) \
|
||||
do \
|
||||
{ \
|
||||
if (!(_condition)) \
|
||||
::boost::throw_exception( \
|
||||
_ExceptionType() << \
|
||||
::solidity::util::errinfo_comment(_description) << \
|
||||
::boost::throw_function(ETH_FUNC) << \
|
||||
::boost::throw_file(__FILE__) << \
|
||||
::boost::throw_line(__LINE__) \
|
||||
); \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
set(sources
|
||||
Algorithms.h
|
||||
AnsiColorized.h
|
||||
Assertions.h
|
||||
Common.h
|
||||
CommonData.cpp
|
||||
CommonData.h
|
||||
CommonIO.cpp
|
||||
CommonIO.h
|
||||
Exceptions.cpp
|
||||
Exceptions.h
|
||||
FixedHash.h
|
||||
IndentedWriter.cpp
|
||||
IndentedWriter.h
|
||||
InvertibleMap.h
|
||||
IpfsHash.cpp
|
||||
IpfsHash.h
|
||||
JSON.cpp
|
||||
JSON.h
|
||||
Keccak256.cpp
|
||||
Keccak256.h
|
||||
picosha2.h
|
||||
Result.h
|
||||
StringUtils.cpp
|
||||
StringUtils.h
|
||||
SwarmHash.cpp
|
||||
SwarmHash.h
|
||||
UTF8.cpp
|
||||
UTF8.h
|
||||
vector_ref.h
|
||||
Visitor.h
|
||||
Whiskers.cpp
|
||||
Whiskers.h
|
||||
)
|
||||
|
||||
add_library(devcore ${sources})
|
||||
target_link_libraries(devcore PUBLIC jsoncpp Boost::boost Boost::filesystem Boost::system)
|
||||
target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}")
|
||||
add_dependencies(devcore solidity_BuildInfo.h)
|
||||
|
||||
if(SOLC_LINK_STATIC)
|
||||
target_link_libraries(devcore PUBLIC Threads::Threads)
|
||||
endif()
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file Common.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*
|
||||
* Very common stuff (i.e. that every other header needs except vector_ref.h).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// way too many unsigned to size_t warnings in 32 bit build
|
||||
#ifdef _M_IX86
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
#if _MSC_VER && _MSC_VER < 1900
|
||||
#define _ALLOW_KEYWORD_MACROS
|
||||
#define noexcept throw()
|
||||
#endif
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning(disable:3682) //call through incomplete class
|
||||
#endif
|
||||
|
||||
#include <libsolutil/vector_ref.h>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if (BOOST_VERSION < 106500)
|
||||
#error "Unsupported Boost version. At least 1.65 required."
|
||||
#endif
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
// Binary data types.
|
||||
using bytes = std::vector<uint8_t>;
|
||||
using bytesRef = util::vector_ref<uint8_t>;
|
||||
using bytesConstRef = util::vector_ref<uint8_t const>;
|
||||
|
||||
// Numeric types.
|
||||
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
|
||||
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
|
||||
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
|
||||
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
|
||||
|
||||
// Map types.
|
||||
using StringMap = std::map<std::string, std::string>;
|
||||
|
||||
// String types.
|
||||
using strings = std::vector<std::string>;
|
||||
|
||||
/// Interprets @a _u as a two's complement signed number and returns the resulting s256.
|
||||
inline s256 u2s(u256 _u)
|
||||
{
|
||||
static bigint const c_end = bigint(1) << 256;
|
||||
if (boost::multiprecision::bit_test(_u, 255))
|
||||
return s256(-(c_end - _u));
|
||||
else
|
||||
return s256(_u);
|
||||
}
|
||||
|
||||
/// @returns the two's complement signed representation of the signed number _u.
|
||||
inline u256 s2u(s256 _u)
|
||||
{
|
||||
static bigint const c_end = bigint(1) << 256;
|
||||
if (_u >= 0)
|
||||
return u256(_u);
|
||||
else
|
||||
return u256(c_end + _u);
|
||||
}
|
||||
|
||||
inline u256 exp256(u256 _base, u256 _exponent)
|
||||
{
|
||||
using boost::multiprecision::limb_type;
|
||||
u256 result = 1;
|
||||
while (_exponent)
|
||||
{
|
||||
if (boost::multiprecision::bit_test(_exponent, 0))
|
||||
result *= _base;
|
||||
_base *= _base;
|
||||
_exponent >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, bytes const& _bytes)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << std::hex;
|
||||
std::copy(_bytes.begin(), _bytes.end(), std::ostream_iterator<int>(ss, ","));
|
||||
std::string result = ss.str();
|
||||
result.pop_back();
|
||||
os << "[" + result + "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
/// RAII utility class whose destructor calls a given function.
|
||||
class ScopeGuard
|
||||
{
|
||||
public:
|
||||
explicit ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
|
||||
~ScopeGuard() { m_f(); }
|
||||
|
||||
private:
|
||||
std::function<void(void)> m_f;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file CommonData.cpp
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <libsolutil/Exceptions.h>
|
||||
#include <libsolutil/Assertions.h>
|
||||
#include <libsolutil/Keccak256.h>
|
||||
#include <libsolutil/FixedHash.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static char const* upperHexChars = "0123456789ABCDEF";
|
||||
static char const* lowerHexChars = "0123456789abcdef";
|
||||
|
||||
}
|
||||
|
||||
string solidity::util::toHex(uint8_t _data, HexCase _case)
|
||||
{
|
||||
assertThrow(_case != HexCase::Mixed, BadHexCase, "Mixed case can only be used for byte arrays.");
|
||||
|
||||
char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
|
||||
|
||||
return std::string{
|
||||
chars[(unsigned(_data) / 16) & 0xf],
|
||||
chars[unsigned(_data) & 0xf]
|
||||
};
|
||||
}
|
||||
|
||||
string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case)
|
||||
{
|
||||
std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0);
|
||||
|
||||
size_t i = 0;
|
||||
if (_prefix == HexPrefix::Add)
|
||||
{
|
||||
ret[i++] = '0';
|
||||
ret[i++] = 'x';
|
||||
}
|
||||
|
||||
// Mixed case will be handled inside the loop.
|
||||
char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
|
||||
int rix = _data.size() - 1;
|
||||
for (uint8_t c: _data)
|
||||
{
|
||||
// switch hex case every four hexchars
|
||||
if (_case == HexCase::Mixed)
|
||||
chars = (rix-- & 2) == 0 ? lowerHexChars : upperHexChars;
|
||||
|
||||
ret[i++] = chars[(unsigned(c) / 16) & 0xf];
|
||||
ret[i++] = chars[unsigned(c) & 0xf];
|
||||
}
|
||||
assertThrow(i == ret.size(), Exception, "");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int solidity::util::fromHex(char _i, WhenError _throw)
|
||||
{
|
||||
if (_i >= '0' && _i <= '9')
|
||||
return _i - '0';
|
||||
if (_i >= 'a' && _i <= 'f')
|
||||
return _i - 'a' + 10;
|
||||
if (_i >= 'A' && _i <= 'F')
|
||||
return _i - 'A' + 10;
|
||||
if (_throw == WhenError::Throw)
|
||||
assertThrow(false, BadHexCharacter, to_string(_i));
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
|
||||
{
|
||||
unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0;
|
||||
std::vector<uint8_t> ret;
|
||||
ret.reserve((_s.size() - s + 1) / 2);
|
||||
|
||||
if (_s.size() % 2)
|
||||
{
|
||||
int h = fromHex(_s[s++], _throw);
|
||||
if (h != -1)
|
||||
ret.push_back(h);
|
||||
else
|
||||
return bytes();
|
||||
}
|
||||
for (unsigned i = s; i < _s.size(); i += 2)
|
||||
{
|
||||
int h = fromHex(_s[i], _throw);
|
||||
int l = fromHex(_s[i + 1], _throw);
|
||||
if (h != -1 && l != -1)
|
||||
ret.push_back((uint8_t)(h * 16 + l));
|
||||
else
|
||||
return bytes();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool solidity::util::passesAddressChecksum(string const& _str, bool _strict)
|
||||
{
|
||||
string s = _str.substr(0, 2) == "0x" ? _str : "0x" + _str;
|
||||
|
||||
if (s.length() != 42)
|
||||
return false;
|
||||
|
||||
if (!_strict && (
|
||||
s.find_first_of("abcdef") == string::npos ||
|
||||
s.find_first_of("ABCDEF") == string::npos
|
||||
))
|
||||
return true;
|
||||
|
||||
return s == solidity::util::getChecksummedAddress(s);
|
||||
}
|
||||
|
||||
string solidity::util::getChecksummedAddress(string const& _addr)
|
||||
{
|
||||
string s = _addr.substr(0, 2) == "0x" ? _addr.substr(2) : _addr;
|
||||
assertThrow(s.length() == 40, InvalidAddress, "");
|
||||
assertThrow(s.find_first_not_of("0123456789abcdefABCDEF") == string::npos, InvalidAddress, "");
|
||||
|
||||
h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
|
||||
|
||||
string ret = "0x";
|
||||
for (size_t i = 0; i < 40; ++i)
|
||||
{
|
||||
char addressCharacter = s[i];
|
||||
unsigned nibble = (unsigned(hash[i / 2]) >> (4 * (1 - (i % 2)))) & 0xf;
|
||||
if (nibble >= 8)
|
||||
ret += toupper(addressCharacter);
|
||||
else
|
||||
ret += tolower(addressCharacter);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool solidity::util::isValidHex(string const& _string)
|
||||
{
|
||||
if (_string.substr(0, 2) != "0x")
|
||||
return false;
|
||||
if (_string.find_first_not_of("0123456789abcdefABCDEF", 2) != string::npos)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool solidity::util::isValidDecimal(string const& _string)
|
||||
{
|
||||
if (_string.empty())
|
||||
return false;
|
||||
if (_string == "0")
|
||||
return true;
|
||||
// No leading zeros
|
||||
if (_string.front() == '0')
|
||||
return false;
|
||||
if (_string.find_first_not_of("0123456789") != string::npos)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
string solidity::util::formatAsStringOrNumber(string const& _value)
|
||||
{
|
||||
assertThrow(_value.length() <= 32, StringTooLong, "String to be formatted longer than 32 bytes.");
|
||||
|
||||
for (auto const& c: _value)
|
||||
if (c <= 0x1f || c >= 0x7f || c == '"')
|
||||
return "0x" + h256(_value, h256::AlignLeft).hex();
|
||||
|
||||
return "\"" + _value + "\"";
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file CommonData.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*
|
||||
* Shared algorithms and data types.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <libsolutil/Common.h>
|
||||
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
/// Operators need to stay in the global namespace.
|
||||
|
||||
/// Concatenate the contents of a container onto a vector
|
||||
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U const& _b)
|
||||
{
|
||||
for (auto const& i: _b)
|
||||
_a.push_back(i);
|
||||
return _a;
|
||||
}
|
||||
/// Concatenate the contents of a container onto a vector, move variant.
|
||||
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U&& _b)
|
||||
{
|
||||
std::move(_b.begin(), _b.end(), std::back_inserter(_a));
|
||||
return _a;
|
||||
}
|
||||
/// Concatenate the contents of a container onto a multiset
|
||||
template <class U, class... T> std::multiset<T...>& operator+=(std::multiset<T...>& _a, U const& _b)
|
||||
{
|
||||
_a.insert(_b.begin(), _b.end());
|
||||
return _a;
|
||||
}
|
||||
/// Concatenate the contents of a container onto a multiset, move variant.
|
||||
template <class U, class... T> std::multiset<T...>& operator+=(std::multiset<T...>& _a, U&& _b)
|
||||
{
|
||||
for (auto&& x: _b)
|
||||
_a.insert(std::move(x));
|
||||
return _a;
|
||||
}
|
||||
/// Concatenate the contents of a container onto a set
|
||||
template <class U, class... T> std::set<T...>& operator+=(std::set<T...>& _a, U const& _b)
|
||||
{
|
||||
_a.insert(_b.begin(), _b.end());
|
||||
return _a;
|
||||
}
|
||||
/// Concatenate the contents of a container onto a set, move variant.
|
||||
template <class U, class... T> std::set<T...>& operator+=(std::set<T...>& _a, U&& _b)
|
||||
{
|
||||
for (auto&& x: _b)
|
||||
_a.insert(std::move(x));
|
||||
return _a;
|
||||
}
|
||||
/// Concatenate two vectors of elements.
|
||||
template <class T>
|
||||
inline std::vector<T> operator+(std::vector<T> const& _a, std::vector<T> const& _b)
|
||||
{
|
||||
std::vector<T> ret(_a);
|
||||
ret += _b;
|
||||
return ret;
|
||||
}
|
||||
/// Concatenate two vectors of elements, moving them.
|
||||
template <class T>
|
||||
inline std::vector<T> operator+(std::vector<T>&& _a, std::vector<T>&& _b)
|
||||
{
|
||||
std::vector<T> ret(std::move(_a));
|
||||
if (&_a == &_b)
|
||||
ret += ret;
|
||||
else
|
||||
ret += std::move(_b);
|
||||
return ret;
|
||||
}
|
||||
/// Concatenate something to a sets of elements.
|
||||
template <class T, class U>
|
||||
inline std::set<T> operator+(std::set<T> const& _a, U&& _b)
|
||||
{
|
||||
std::set<T> ret(_a);
|
||||
ret += std::forward<U>(_b);
|
||||
return ret;
|
||||
}
|
||||
/// Concatenate something to a sets of elements, move variant.
|
||||
template <class T, class U>
|
||||
inline std::set<T> operator+(std::set<T>&& _a, U&& _b)
|
||||
{
|
||||
std::set<T> ret(std::move(_a));
|
||||
ret += std::forward<U>(_b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Remove the elements of a container from a set.
|
||||
template <class C, class... T>
|
||||
inline std::set<T...>& operator-=(std::set<T...>& _a, C const& _b)
|
||||
{
|
||||
for (auto const& x: _b)
|
||||
_a.erase(x);
|
||||
return _a;
|
||||
}
|
||||
|
||||
template <class C, class... T>
|
||||
inline std::set<T...> operator-(std::set<T...> const& _a, C const& _b)
|
||||
{
|
||||
auto result = _a;
|
||||
result -= _b;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Remove the elements of a container from a multiset.
|
||||
template <class C, class... T>
|
||||
inline std::multiset<T...>& operator-=(std::multiset<T...>& _a, C const& _b)
|
||||
{
|
||||
for (auto const& x: _b)
|
||||
_a.erase(x);
|
||||
return _a;
|
||||
}
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
template <class T, class U>
|
||||
T convertContainer(U const& _from)
|
||||
{
|
||||
return T{_from.cbegin(), _from.cend()};
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
T convertContainer(U&& _from)
|
||||
{
|
||||
return T{
|
||||
std::make_move_iterator(_from.begin()),
|
||||
std::make_move_iterator(_from.end())
|
||||
};
|
||||
}
|
||||
|
||||
// String conversion functions, mainly to/from hex/nibble/byte representations.
|
||||
|
||||
enum class WhenError
|
||||
{
|
||||
DontThrow = 0,
|
||||
Throw = 1,
|
||||
};
|
||||
|
||||
enum class HexPrefix
|
||||
{
|
||||
DontAdd = 0,
|
||||
Add = 1,
|
||||
};
|
||||
|
||||
enum class HexCase
|
||||
{
|
||||
Lower = 0,
|
||||
Upper = 1,
|
||||
Mixed = 2,
|
||||
};
|
||||
|
||||
/// Convert a single byte to a string of hex characters (of length two),
|
||||
/// optionally with uppercase hex letters.
|
||||
std::string toHex(uint8_t _data, HexCase _case = HexCase::Lower);
|
||||
|
||||
/// Convert a series of bytes to the corresponding string of hex duplets,
|
||||
/// optionally with "0x" prefix and with uppercase hex letters.
|
||||
std::string toHex(bytes const& _data, HexPrefix _prefix = HexPrefix::DontAdd, HexCase _case = HexCase::Lower);
|
||||
|
||||
/// Converts a (printable) ASCII hex character into the corresponding integer value.
|
||||
/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5
|
||||
int fromHex(char _i, WhenError _throw);
|
||||
|
||||
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
|
||||
/// @example fromHex("41626261") == asBytes("Abba")
|
||||
/// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception.
|
||||
bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow);
|
||||
/// Converts byte array to a string containing the same (binary) data. Unless
|
||||
/// the byte array happens to contain ASCII data, this won't be printable.
|
||||
inline std::string asString(bytes const& _b)
|
||||
{
|
||||
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
|
||||
}
|
||||
|
||||
/// Converts byte array ref to a string containing the same (binary) data. Unless
|
||||
/// the byte array happens to contain ASCII data, this won't be printable.
|
||||
inline std::string asString(bytesConstRef _b)
|
||||
{
|
||||
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
|
||||
}
|
||||
|
||||
/// Converts a string to a byte array containing the string's (byte) data.
|
||||
inline bytes asBytes(std::string const& _b)
|
||||
{
|
||||
return bytes((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size()));
|
||||
}
|
||||
|
||||
// Big-endian to/from host endian conversion functions.
|
||||
|
||||
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
|
||||
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
|
||||
/// value properly, if too big then the additional elements will be zeroed out.
|
||||
/// @a Out will typically be either std::string or bytes.
|
||||
/// @a T will typically by unsigned, u160, u256 or bigint.
|
||||
template <class T, class Out>
|
||||
inline void toBigEndian(T _val, Out& o_out)
|
||||
{
|
||||
static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
|
||||
for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
|
||||
{
|
||||
T v = _val & (T)0xff;
|
||||
o_out[i - 1] = (typename Out::value_type)(uint8_t)v;
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
|
||||
/// @a _In will typically be either std::string or bytes.
|
||||
/// @a T will typically by unsigned, u160, u256 or bigint.
|
||||
template <class T, class _In>
|
||||
inline T fromBigEndian(_In const& _bytes)
|
||||
{
|
||||
T ret = (T)0;
|
||||
for (auto i: _bytes)
|
||||
ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned<typename _In::value_type>::type)i);
|
||||
return ret;
|
||||
}
|
||||
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
|
||||
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
|
||||
|
||||
/// Convenience function for toBigEndian.
|
||||
/// @returns a byte array just big enough to represent @a _val.
|
||||
template <class T>
|
||||
inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
|
||||
{
|
||||
static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
|
||||
int i = 0;
|
||||
for (T v = _val; v; ++i, v >>= 8) {}
|
||||
bytes ret(std::max<unsigned>(_min, i), 0);
|
||||
toBigEndian(_val, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Convenience function for conversion of a u256 to hex
|
||||
inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd)
|
||||
{
|
||||
std::string str = toHex(toBigEndian(val));
|
||||
return (prefix == HexPrefix::Add) ? "0x" + str : str;
|
||||
}
|
||||
|
||||
inline std::string toCompactHexWithPrefix(u256 const& _value)
|
||||
{
|
||||
return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add);
|
||||
}
|
||||
|
||||
/// Returns decimal representation for small numbers and hex for large numbers.
|
||||
inline std::string formatNumber(bigint const& _value)
|
||||
{
|
||||
if (_value < 0)
|
||||
return "-" + formatNumber(-_value);
|
||||
if (_value > 0x1000000)
|
||||
return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add);
|
||||
else
|
||||
return _value.str();
|
||||
}
|
||||
|
||||
inline std::string formatNumber(u256 const& _value)
|
||||
{
|
||||
if (_value > 0x1000000)
|
||||
return toCompactHexWithPrefix(_value);
|
||||
else
|
||||
return _value.str();
|
||||
}
|
||||
|
||||
|
||||
// Algorithms for string and string-like collections.
|
||||
|
||||
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
|
||||
template <class T>
|
||||
inline unsigned bytesRequired(T _i)
|
||||
{
|
||||
static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
|
||||
unsigned i = 0;
|
||||
for (; _i != 0; ++i, _i >>= 8) {}
|
||||
return i;
|
||||
}
|
||||
template <class T, class V>
|
||||
bool contains(T const& _t, V const& _v)
|
||||
{
|
||||
return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v);
|
||||
}
|
||||
|
||||
template <class T, class Predicate>
|
||||
bool contains_if(T const& _t, Predicate const& _p)
|
||||
{
|
||||
return std::end(_t) != std::find_if(std::begin(_t), std::end(_t), _p);
|
||||
}
|
||||
|
||||
/// Function that iterates over a vector, calling a function on each of its
|
||||
/// elements. If that function returns a vector, the element is replaced by
|
||||
/// the returned vector. During the iteration, the original vector is only valid
|
||||
/// on the current element and after that. The actual replacement takes
|
||||
/// place at the end, but already visited elements might be invalidated.
|
||||
/// If nothing is replaced, no copy is performed.
|
||||
template <typename T, typename F>
|
||||
void iterateReplacing(std::vector<T>& _vector, F const& _f)
|
||||
{
|
||||
// Concept: _f must be Callable, must accept param T&, must return optional<vector<T>>
|
||||
bool useModified = false;
|
||||
std::vector<T> modifiedVector;
|
||||
for (size_t i = 0; i < _vector.size(); ++i)
|
||||
{
|
||||
if (std::optional<std::vector<T>> r = _f(_vector[i]))
|
||||
{
|
||||
if (!useModified)
|
||||
{
|
||||
std::move(_vector.begin(), _vector.begin() + i, back_inserter(modifiedVector));
|
||||
useModified = true;
|
||||
}
|
||||
modifiedVector += std::move(*r);
|
||||
}
|
||||
else if (useModified)
|
||||
modifiedVector.emplace_back(std::move(_vector[i]));
|
||||
}
|
||||
if (useModified)
|
||||
_vector = std::move(modifiedVector);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename F, std::size_t... I>
|
||||
void iterateReplacingWindow(std::vector<T>& _vector, F const& _f, std::index_sequence<I...>)
|
||||
{
|
||||
// Concept: _f must be Callable, must accept sizeof...(I) parameters of type T&, must return optional<vector<T>>
|
||||
bool useModified = false;
|
||||
std::vector<T> modifiedVector;
|
||||
size_t i = 0;
|
||||
for (; i + sizeof...(I) <= _vector.size(); ++i)
|
||||
{
|
||||
if (std::optional<std::vector<T>> r = _f(_vector[i + I]...))
|
||||
{
|
||||
if (!useModified)
|
||||
{
|
||||
std::move(_vector.begin(), _vector.begin() + i, back_inserter(modifiedVector));
|
||||
useModified = true;
|
||||
}
|
||||
modifiedVector += std::move(*r);
|
||||
i += sizeof...(I) - 1;
|
||||
}
|
||||
else if (useModified)
|
||||
modifiedVector.emplace_back(std::move(_vector[i]));
|
||||
}
|
||||
if (useModified)
|
||||
{
|
||||
for (; i < _vector.size(); ++i)
|
||||
modifiedVector.emplace_back(std::move(_vector[i]));
|
||||
_vector = std::move(modifiedVector);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Function that iterates over the vector @param _vector,
|
||||
/// calling the function @param _f on sequences of @tparam N of its
|
||||
/// elements. If @param _f returns a vector, these elements are replaced by
|
||||
/// the returned vector and the iteration continues with the next @tparam N elements.
|
||||
/// If the function does not return a vector, the iteration continues with an overlapping
|
||||
/// sequence of @tparam N elements that starts with the second element of the previous
|
||||
/// iteration.
|
||||
/// During the iteration, the original vector is only valid
|
||||
/// on the current element and after that. The actual replacement takes
|
||||
/// place at the end, but already visited elements might be invalidated.
|
||||
/// If nothing is replaced, no copy is performed.
|
||||
template <std::size_t N, typename T, typename F>
|
||||
void iterateReplacingWindow(std::vector<T>& _vector, F const& _f)
|
||||
{
|
||||
// Concept: _f must be Callable, must accept N parameters of type T&, must return optional<vector<T>>
|
||||
detail::iterateReplacingWindow(_vector, _f, std::make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
/// @returns true iff @a _str passess the hex address checksum test.
|
||||
/// @param _strict if false, hex strings with only uppercase or only lowercase letters
|
||||
/// are considered valid.
|
||||
bool passesAddressChecksum(std::string const& _str, bool _strict);
|
||||
|
||||
/// @returns the checksummed version of an address
|
||||
/// @param hex strings that look like an address
|
||||
std::string getChecksummedAddress(std::string const& _addr);
|
||||
|
||||
bool isValidHex(std::string const& _string);
|
||||
bool isValidDecimal(std::string const& _string);
|
||||
|
||||
/// @returns a quoted string if all characters are printable ASCII chars,
|
||||
/// or its hex representation otherwise.
|
||||
/// _value cannot be longer than 32 bytes.
|
||||
std::string formatAsStringOrNumber(std::string const& _value);
|
||||
|
||||
template<typename Container, typename Compare>
|
||||
bool containerEqual(Container const& _lhs, Container const& _rhs, Compare&& _compare)
|
||||
{
|
||||
return std::equal(std::begin(_lhs), std::end(_lhs), std::begin(_rhs), std::end(_rhs), std::forward<Compare>(_compare));
|
||||
}
|
||||
|
||||
inline std::string findAnyOf(std::string const& _haystack, std::vector<std::string> const& _needles)
|
||||
{
|
||||
for (std::string const& needle: _needles)
|
||||
if (_haystack.find(needle) != std::string::npos)
|
||||
return needle;
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
void variadicEmplaceBack(std::vector<T>&) {}
|
||||
template<typename T, typename A, typename... Args>
|
||||
void variadicEmplaceBack(std::vector<T>& _vector, A&& _a, Args&&... _args)
|
||||
{
|
||||
_vector.emplace_back(std::forward<A>(_a));
|
||||
variadicEmplaceBack(_vector, std::forward<Args>(_args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
std::vector<T> make_vector(Args&&... _args)
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.reserve(sizeof...(_args));
|
||||
detail::variadicEmplaceBack(result, std::forward<Args>(_args)...);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file CommonIO.cpp
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libsolutil/Assertions.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename _T>
|
||||
inline _T readFile(std::string const& _file)
|
||||
{
|
||||
_T ret;
|
||||
size_t const c_elementSize = sizeof(typename _T::value_type);
|
||||
std::ifstream is(_file, std::ifstream::binary);
|
||||
if (!is)
|
||||
return ret;
|
||||
|
||||
// get length of file:
|
||||
is.seekg(0, is.end);
|
||||
streamoff length = is.tellg();
|
||||
if (length == 0)
|
||||
return ret; // do not read empty file (MSVC does not like it)
|
||||
is.seekg(0, is.beg);
|
||||
|
||||
ret.resize((length + c_elementSize - 1) / c_elementSize);
|
||||
is.read(const_cast<char*>(reinterpret_cast<char const*>(ret.data())), length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string solidity::util::readFileAsString(string const& _file)
|
||||
{
|
||||
return readFile<string>(_file);
|
||||
}
|
||||
|
||||
string solidity::util::readStandardInput()
|
||||
{
|
||||
string ret;
|
||||
while (!cin.eof())
|
||||
{
|
||||
string tmp;
|
||||
// NOTE: this will read until EOF or NL
|
||||
getline(cin, tmp);
|
||||
ret.append(tmp);
|
||||
ret.append("\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
class DisableConsoleBuffering
|
||||
{
|
||||
public:
|
||||
DisableConsoleBuffering()
|
||||
{
|
||||
m_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
GetConsoleMode(m_stdin, &m_oldMode);
|
||||
SetConsoleMode(m_stdin, m_oldMode & (~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT)));
|
||||
}
|
||||
~DisableConsoleBuffering()
|
||||
{
|
||||
SetConsoleMode(m_stdin, m_oldMode);
|
||||
}
|
||||
private:
|
||||
HANDLE m_stdin;
|
||||
DWORD m_oldMode;
|
||||
};
|
||||
#else
|
||||
class DisableConsoleBuffering
|
||||
{
|
||||
public:
|
||||
DisableConsoleBuffering()
|
||||
{
|
||||
tcgetattr(0, &m_termios);
|
||||
m_termios.c_lflag &= ~ICANON;
|
||||
m_termios.c_lflag &= ~ECHO;
|
||||
m_termios.c_cc[VMIN] = 1;
|
||||
m_termios.c_cc[VTIME] = 0;
|
||||
tcsetattr(0, TCSANOW, &m_termios);
|
||||
}
|
||||
~DisableConsoleBuffering()
|
||||
{
|
||||
m_termios.c_lflag |= ICANON;
|
||||
m_termios.c_lflag |= ECHO;
|
||||
tcsetattr(0, TCSADRAIN, &m_termios);
|
||||
}
|
||||
private:
|
||||
struct termios m_termios;
|
||||
};
|
||||
#endif
|
||||
|
||||
int solidity::util::readStandardInputChar()
|
||||
{
|
||||
DisableConsoleBuffering disableConsoleBuffering;
|
||||
return cin.get();
|
||||
}
|
||||
|
||||
string solidity::util::absolutePath(string const& _path, string const& _reference)
|
||||
{
|
||||
boost::filesystem::path p(_path);
|
||||
// Anything that does not start with `.` is an absolute path.
|
||||
if (p.begin() == p.end() || (*p.begin() != "." && *p.begin() != ".."))
|
||||
return _path;
|
||||
boost::filesystem::path result(_reference);
|
||||
result.remove_filename();
|
||||
for (boost::filesystem::path::iterator it = p.begin(); it != p.end(); ++it)
|
||||
if (*it == "..")
|
||||
result = result.parent_path();
|
||||
else if (*it != ".")
|
||||
result /= *it;
|
||||
return result.generic_string();
|
||||
}
|
||||
|
||||
string solidity::util::sanitizePath(string const& _path) {
|
||||
return boost::filesystem::path(_path).generic_string();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file CommonIO.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*
|
||||
* File & stream I/O routines.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Retrieve and returns the contents of the given file as a std::string.
|
||||
/// If the file doesn't exist or isn't readable, returns an empty container / bytes.
|
||||
std::string readFileAsString(std::string const& _file);
|
||||
|
||||
/// Retrieve and returns the contents of standard input (until EOF).
|
||||
std::string readStandardInput();
|
||||
|
||||
/// Retrieve and returns a character from standard input (without waiting for EOL).
|
||||
int readStandardInputChar();
|
||||
|
||||
/// Converts arbitrary value to string representation using std::stringstream.
|
||||
template <class _T>
|
||||
std::string toString(_T const& _t)
|
||||
{
|
||||
std::ostringstream o;
|
||||
o << _t;
|
||||
return o.str();
|
||||
}
|
||||
|
||||
/// @returns the absolute path corresponding to @a _path relative to @a _reference.
|
||||
std::string absolutePath(std::string const& _path, std::string const& _reference);
|
||||
|
||||
/// Helper function to return path converted strings.
|
||||
std::string sanitizePath(std::string const& _path);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
|
||||
char const* Exception::what() const noexcept
|
||||
{
|
||||
// Return the comment if available.
|
||||
if (string const* cmt = comment())
|
||||
return cmt->data();
|
||||
|
||||
// Fallback to base what().
|
||||
// Boost accepts nullptr, but the C++ standard doesn't
|
||||
// and crashes on some platforms.
|
||||
return std::exception::what();
|
||||
}
|
||||
|
||||
string Exception::lineInfo() const
|
||||
{
|
||||
char const* const* file = boost::get_error_info<boost::throw_file>(*this);
|
||||
int const* line = boost::get_error_info<boost::throw_line>(*this);
|
||||
string ret;
|
||||
if (file)
|
||||
ret += *file;
|
||||
ret += ':';
|
||||
if (line)
|
||||
ret += to_string(*line);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string const* Exception::comment() const noexcept
|
||||
{
|
||||
return boost::get_error_info<errinfo_comment>(*this);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/exception/exception.hpp>
|
||||
#include <boost/exception/info.hpp>
|
||||
#include <boost/exception/info_tuple.hpp>
|
||||
#include <boost/exception/diagnostic_information.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Base class for all exceptions.
|
||||
struct Exception: virtual std::exception, virtual boost::exception
|
||||
{
|
||||
char const* what() const noexcept override;
|
||||
|
||||
/// @returns "FileName:LineNumber" referring to the point where the exception was thrown.
|
||||
std::string lineInfo() const;
|
||||
|
||||
/// @returns the errinfo_comment of this exception.
|
||||
std::string const* comment() const noexcept;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual ::solidity::util::Exception { const char* what() const noexcept override { return #X; } }
|
||||
|
||||
DEV_SIMPLE_EXCEPTION(InvalidAddress);
|
||||
DEV_SIMPLE_EXCEPTION(BadHexCharacter);
|
||||
DEV_SIMPLE_EXCEPTION(BadHexCase);
|
||||
DEV_SIMPLE_EXCEPTION(FileError);
|
||||
DEV_SIMPLE_EXCEPTION(DataTooLong);
|
||||
DEV_SIMPLE_EXCEPTION(StringTooLong);
|
||||
|
||||
// error information to be added to exceptions
|
||||
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file FixedHash.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*
|
||||
* The FixedHash fixed-size "hash" container type.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
|
||||
/// Transparently converts to/from the corresponding arithmetic type; this will
|
||||
/// assume the data contained in the hash is big-endian.
|
||||
template <unsigned N>
|
||||
class FixedHash
|
||||
{
|
||||
public:
|
||||
/// The corresponding arithmetic type.
|
||||
using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
|
||||
|
||||
/// The size of the container.
|
||||
enum { size = N };
|
||||
|
||||
/// Method to convert from a string.
|
||||
enum ConstructFromStringType { FromHex, FromBinary };
|
||||
|
||||
/// Method to convert from a string.
|
||||
enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent };
|
||||
|
||||
/// Construct an empty hash.
|
||||
explicit FixedHash() { m_data.fill(0); }
|
||||
|
||||
/// Construct from another hash, filling with zeroes or cropping as necessary.
|
||||
template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
|
||||
|
||||
/// Convert from the corresponding arithmetic type.
|
||||
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
|
||||
|
||||
/// Convert from unsigned
|
||||
explicit FixedHash(unsigned _u) { toBigEndian(_u, m_data); }
|
||||
|
||||
/// Explicitly construct, copying from a byte array.
|
||||
explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
|
||||
|
||||
/// Explicitly construct, copying from a byte array.
|
||||
explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
|
||||
|
||||
/// Explicitly construct, copying from a string.
|
||||
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : solidity::util::asBytes(_s), _ht) {}
|
||||
|
||||
/// Convert to arithmetic type.
|
||||
operator Arith() const { return fromBigEndian<Arith>(m_data); }
|
||||
|
||||
/// @returns true iff this is the empty hash.
|
||||
explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](uint8_t _b) { return _b != 0; }); }
|
||||
|
||||
// The obvious comparison operators.
|
||||
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
|
||||
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
|
||||
/// Required to sort objects of this type or use them as map keys.
|
||||
bool operator<(FixedHash const& _c) const { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; }
|
||||
|
||||
FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; }
|
||||
|
||||
/// @returns a particular byte from the hash.
|
||||
uint8_t& operator[](unsigned _i) { return m_data[_i]; }
|
||||
/// @returns a particular byte from the hash.
|
||||
uint8_t operator[](unsigned _i) const { return m_data[_i]; }
|
||||
|
||||
/// @returns the hash as a user-readable hex string.
|
||||
std::string hex() const { return toHex(asBytes()); }
|
||||
|
||||
/// @returns a mutable byte vector_ref to the object's data.
|
||||
bytesRef ref() { return bytesRef(m_data.data(), N); }
|
||||
|
||||
/// @returns a constant byte vector_ref to the object's data.
|
||||
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
|
||||
|
||||
/// @returns a mutable byte pointer to the object's data.
|
||||
uint8_t* data() { return m_data.data(); }
|
||||
|
||||
/// @returns a constant byte pointer to the object's data.
|
||||
uint8_t const* data() const { return m_data.data(); }
|
||||
|
||||
/// @returns a copy of the object's data as a byte vector.
|
||||
bytes asBytes() const { return bytes(data(), data() + N); }
|
||||
|
||||
/// @returns a mutable reference to the object's data as an STL array.
|
||||
std::array<uint8_t, N>& asArray() { return m_data; }
|
||||
|
||||
/// @returns a constant reference to the object's data as an STL array.
|
||||
std::array<uint8_t, N> const& asArray() const { return m_data; }
|
||||
|
||||
/// Returns the index of the first bit set to one, or size() * 8 if no bits are set.
|
||||
inline unsigned firstBitSet() const
|
||||
{
|
||||
unsigned ret = 0;
|
||||
for (auto d: m_data)
|
||||
if (d)
|
||||
{
|
||||
for (;; ++ret, d <<= 1)
|
||||
if (d & 0x80)
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
ret += 8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void clear() { m_data.fill(0); }
|
||||
|
||||
private:
|
||||
std::array<uint8_t, N> m_data; ///< The binary data.
|
||||
};
|
||||
|
||||
/// Stream I/O for the FixedHash class.
|
||||
template <unsigned N>
|
||||
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
|
||||
{
|
||||
boost::io::ios_all_saver guard(_out);
|
||||
_out << std::noshowbase << std::hex << std::setfill('0');
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
_out << std::setw(2) << (int)_h[i];
|
||||
_out << std::dec;
|
||||
return _out;
|
||||
}
|
||||
|
||||
// Common types of FixedHash.
|
||||
using h256 = FixedHash<32>;
|
||||
using h160 = FixedHash<20>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @date 2017
|
||||
* Indented text writer.
|
||||
*/
|
||||
|
||||
#include <libsolutil/IndentedWriter.h>
|
||||
#include <libsolutil/Assertions.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
|
||||
string IndentedWriter::format() const
|
||||
{
|
||||
string result;
|
||||
for (auto const& line: m_lines)
|
||||
result += string(line.indentation * 4, ' ') + line.contents + "\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
void IndentedWriter::newLine()
|
||||
{
|
||||
if (!m_lines.back().contents.empty())
|
||||
m_lines.emplace_back(Line{string(), m_lines.back().indentation});
|
||||
}
|
||||
|
||||
void IndentedWriter::indent()
|
||||
{
|
||||
newLine();
|
||||
m_lines.back().indentation++;
|
||||
}
|
||||
|
||||
void IndentedWriter::unindent()
|
||||
{
|
||||
newLine();
|
||||
assertThrow(m_lines.back().indentation > 0, IndentedWriterError, "Negative indentation.");
|
||||
m_lines.back().indentation--;
|
||||
}
|
||||
|
||||
void IndentedWriter::add(string const& _str)
|
||||
{
|
||||
m_lines.back().contents += _str;
|
||||
}
|
||||
|
||||
void IndentedWriter::addLine(string const& _line)
|
||||
{
|
||||
newLine();
|
||||
add(_line);
|
||||
newLine();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @date 2017
|
||||
* Indented text writer.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
DEV_SIMPLE_EXCEPTION(IndentedWriterError);
|
||||
|
||||
class IndentedWriter
|
||||
{
|
||||
public:
|
||||
// Returns the formatted output.
|
||||
std::string format() const;
|
||||
|
||||
// Go one indentation level in.
|
||||
void indent();
|
||||
|
||||
// Go one indentation level out.
|
||||
void unindent();
|
||||
|
||||
// Add text.
|
||||
void add(std::string const& _str);
|
||||
|
||||
// Add text with new line.
|
||||
void addLine(std::string const& _line);
|
||||
|
||||
// Add new line.
|
||||
void newLine();
|
||||
|
||||
private:
|
||||
struct Line
|
||||
{
|
||||
std::string contents;
|
||||
unsigned indentation;
|
||||
};
|
||||
|
||||
std::vector<Line> m_lines{{std::string(), 0}};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
/**
|
||||
* Data structure that keeps track of values and keys of a mapping.
|
||||
*/
|
||||
template <class K, class V>
|
||||
struct InvertibleMap
|
||||
{
|
||||
std::map<K, V> values;
|
||||
// references[x] == {y | values[y] == x}
|
||||
std::map<V, std::set<K>> references;
|
||||
|
||||
void set(K _key, V _value)
|
||||
{
|
||||
if (values.count(_key))
|
||||
references[values[_key]].erase(_key);
|
||||
values[_key] = _value;
|
||||
references[_value].insert(_key);
|
||||
}
|
||||
|
||||
void eraseKey(K _key)
|
||||
{
|
||||
if (values.count(_key))
|
||||
references[values[_key]].erase(_key);
|
||||
values.erase(_key);
|
||||
}
|
||||
|
||||
void eraseValue(V _value)
|
||||
{
|
||||
if (references.count(_value))
|
||||
{
|
||||
for (V v: references[_value])
|
||||
values.erase(v);
|
||||
references.erase(_value);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
values.clear();
|
||||
references.clear();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct InvertibleRelation
|
||||
{
|
||||
/// forward[x] contains y <=> backward[y] contains x
|
||||
std::map<T, std::set<T>> forward;
|
||||
std::map<T, std::set<T>> backward;
|
||||
|
||||
void insert(T _key, T _value)
|
||||
{
|
||||
forward[_key].insert(_value);
|
||||
backward[_value].insert(_key);
|
||||
}
|
||||
|
||||
void set(T _key, std::set<T> _values)
|
||||
{
|
||||
for (T v: forward[_key])
|
||||
backward[v].erase(_key);
|
||||
for (T v: _values)
|
||||
backward[v].insert(_key);
|
||||
forward[_key] = std::move(_values);
|
||||
}
|
||||
|
||||
void eraseKey(T _key)
|
||||
{
|
||||
for (auto const& v: forward[_key])
|
||||
backward[v].erase(_key);
|
||||
forward.erase(_key);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolutil/IpfsHash.h>
|
||||
|
||||
#include <libsolutil/Assertions.h>
|
||||
#include <libsolutil/Exceptions.h>
|
||||
#include <libsolutil/picosha2.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
|
||||
namespace
|
||||
{
|
||||
bytes varintEncoding(size_t _n)
|
||||
{
|
||||
bytes encoded;
|
||||
while (_n > 0x7f)
|
||||
{
|
||||
encoded.emplace_back(uint8_t(0x80 | (_n & 0x7f)));
|
||||
_n >>= 7;
|
||||
}
|
||||
encoded.emplace_back(_n);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
string base58Encode(bytes const& _data)
|
||||
{
|
||||
static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"};
|
||||
bigint data(toHex(_data, HexPrefix::Add));
|
||||
string output;
|
||||
while (data)
|
||||
{
|
||||
output += alphabet[size_t(data % alphabet.size())];
|
||||
data /= alphabet.size();
|
||||
}
|
||||
reverse(output.begin(), output.end());
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
bytes solidity::util::ipfsHash(string _data)
|
||||
{
|
||||
assertThrow(_data.length() < 1024 * 256, DataTooLong, "IPFS hash for large (chunked) files not yet implemented.");
|
||||
|
||||
bytes lengthAsVarint = varintEncoding(_data.size());
|
||||
|
||||
bytes protobufEncodedData;
|
||||
// Type: File
|
||||
protobufEncodedData += bytes{0x08, 0x02};
|
||||
if (!_data.empty())
|
||||
{
|
||||
// Data (length delimited bytes)
|
||||
protobufEncodedData += bytes{0x12};
|
||||
protobufEncodedData += lengthAsVarint;
|
||||
protobufEncodedData += asBytes(std::move(_data));
|
||||
}
|
||||
// filesize: length as varint
|
||||
protobufEncodedData += bytes{0x18} + lengthAsVarint;
|
||||
|
||||
// PBDag:
|
||||
// Data: (length delimited bytes)
|
||||
size_t protobufLength = protobufEncodedData.size();
|
||||
bytes blockData = bytes{0x0a} + varintEncoding(protobufLength) + std::move(protobufEncodedData);
|
||||
// TODO Handle "large" files with multiple blocks
|
||||
|
||||
// Multihash: sha2-256, 256 bits
|
||||
bytes hash = bytes{0x12, 0x20} + picosha2::hash256(std::move(blockData));
|
||||
return hash;
|
||||
}
|
||||
|
||||
string solidity::util::ipfsHashBase58(string _data)
|
||||
{
|
||||
return base58Encode(ipfsHash(std::move(_data)));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Compute the "ipfs hash" of a file with the content @a _data.
|
||||
/// The output will be the multihash of the UnixFS protobuf encoded data.
|
||||
/// As hash function it will use sha2-256.
|
||||
/// The effect is that the hash should be identical to the one produced by
|
||||
/// the command `ipfs add <filename>`.
|
||||
bytes ipfsHash(std::string _data);
|
||||
|
||||
/// Compute the "ipfs hash" as above, but encoded in base58 as used by ipfs / bitcoin.
|
||||
std::string ipfsHashBase58(std::string _data);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file JSON.cpp
|
||||
* @author Alexander Arlt <alexander.arlt@arlt-labs.com>
|
||||
* @date 2018
|
||||
*/
|
||||
|
||||
#include <libsolutil/JSON.h>
|
||||
|
||||
#include <libsolutil/CommonIO.h>
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static_assert(
|
||||
(JSONCPP_VERSION_MAJOR == 1) && (JSONCPP_VERSION_MINOR == 9) && (JSONCPP_VERSION_PATCH == 2),
|
||||
"Unexpected jsoncpp version: " JSONCPP_VERSION_STRING ". Expecting 1.9.2."
|
||||
);
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/// StreamWriterBuilder that can be constructed with specific settings
|
||||
class StreamWriterBuilder: public Json::StreamWriterBuilder
|
||||
{
|
||||
public:
|
||||
explicit StreamWriterBuilder(map<string, Json::Value> const& _settings)
|
||||
{
|
||||
for (auto const& iter: _settings)
|
||||
this->settings_[iter.first] = iter.second;
|
||||
}
|
||||
};
|
||||
|
||||
/// CharReaderBuilder with strict-mode settings
|
||||
class StrictModeCharReaderBuilder: public Json::CharReaderBuilder
|
||||
{
|
||||
public:
|
||||
StrictModeCharReaderBuilder()
|
||||
{
|
||||
Json::CharReaderBuilder::strictMode(&this->settings_);
|
||||
}
|
||||
};
|
||||
|
||||
/// Serialise the JSON object (@a _input) with specific builder (@a _builder)
|
||||
/// \param _input JSON input string
|
||||
/// \param _builder StreamWriterBuilder that is used to create new Json::StreamWriter
|
||||
/// \return serialized json object
|
||||
string print(Json::Value const& _input, Json::StreamWriterBuilder const& _builder)
|
||||
{
|
||||
stringstream stream;
|
||||
unique_ptr<Json::StreamWriter> writer(_builder.newStreamWriter());
|
||||
writer->write(_input, &stream);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
/// Parse a JSON string (@a _input) with specified builder (@ _builder) and writes resulting JSON object to (@a _json)
|
||||
/// \param _builder CharReaderBuilder that is used to create new Json::CharReaders
|
||||
/// \param _input JSON input string
|
||||
/// \param _json [out] resulting JSON object
|
||||
/// \param _errs [out] Formatted error messages
|
||||
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
bool parse(Json::CharReaderBuilder& _builder, string const& _input, Json::Value& _json, string* _errs)
|
||||
{
|
||||
unique_ptr<Json::CharReader> reader(_builder.newCharReader());
|
||||
return reader->parse(_input.c_str(), _input.c_str() + _input.length(), &_json, _errs);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
string jsonPrettyPrint(Json::Value const& _input)
|
||||
{
|
||||
static map<string, Json::Value> settings{{"indentation", " "}, {"enableYAMLCompatibility", true}};
|
||||
static StreamWriterBuilder writerBuilder(settings);
|
||||
string result = print(_input, writerBuilder);
|
||||
boost::replace_all(result, " \n", "\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
string jsonCompactPrint(Json::Value const& _input)
|
||||
{
|
||||
static map<string, Json::Value> settings{{"indentation", ""}};
|
||||
static StreamWriterBuilder writerBuilder(settings);
|
||||
return print(_input, writerBuilder);
|
||||
}
|
||||
|
||||
bool jsonParseStrict(string const& _input, Json::Value& _json, string* _errs /* = nullptr */)
|
||||
{
|
||||
static StrictModeCharReaderBuilder readerBuilder;
|
||||
return parse(readerBuilder, _input, _json, _errs);
|
||||
}
|
||||
|
||||
} // namespace solidity::util
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file JSON.h
|
||||
* @date 2016
|
||||
*
|
||||
* JSON related helpers
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util {
|
||||
|
||||
/// Serialise the JSON object (@a _input) with indentation
|
||||
std::string jsonPrettyPrint(Json::Value const& _input);
|
||||
|
||||
/// Serialise the JSON object (@a _input) without indentation
|
||||
std::string jsonCompactPrint(Json::Value const& _input);
|
||||
|
||||
/// Parse a JSON string (@a _input) with enabled strict-mode and writes resulting JSON object to (@a _json)
|
||||
/// \param _input JSON input string
|
||||
/// \param _json [out] resulting JSON object
|
||||
/// \param _errs [out] Formatted error messages
|
||||
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
bool jsonParseStrict(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file SHA3.cpp
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include <libsolutil/Keccak256.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/** libkeccak-tiny
|
||||
*
|
||||
* A single-file implementation of SHA-3 and SHAKE.
|
||||
*
|
||||
* Implementor: David Leon Gil
|
||||
* License: CC0, attribution kindly requested. Blame taken too,
|
||||
* but not liability.
|
||||
*/
|
||||
|
||||
/******** The Keccak-f[1600] permutation ********/
|
||||
|
||||
/*** Constants. ***/
|
||||
static uint8_t const rho[24] = \
|
||||
{ 1, 3, 6, 10, 15, 21,
|
||||
28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43,
|
||||
62, 18, 39, 61, 20, 44};
|
||||
static uint8_t const pi[24] = \
|
||||
{10, 7, 11, 17, 18, 3,
|
||||
5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2,
|
||||
20, 14, 22, 9, 6, 1};
|
||||
static uint64_t const RC[24] = \
|
||||
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
|
||||
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
|
||||
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
|
||||
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
|
||||
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
|
||||
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
|
||||
|
||||
/*** Helper macros to unroll the permutation. ***/
|
||||
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
|
||||
#define REPEAT6(e) e e e e e e
|
||||
#define REPEAT24(e) REPEAT6(e e e e)
|
||||
#define REPEAT5(e) e e e e e
|
||||
#define FOR5(v, s, e) \
|
||||
v = 0; \
|
||||
REPEAT5(e; v += s;)
|
||||
|
||||
/*** Keccak-f[1600] ***/
|
||||
static inline void keccakf(void* state) {
|
||||
uint64_t* a = (uint64_t*)state;
|
||||
uint64_t b[5] = {0};
|
||||
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
uint8_t x, y;
|
||||
// Theta
|
||||
FOR5(x, 1,
|
||||
b[x] = 0;
|
||||
FOR5(y, 5,
|
||||
b[x] ^= a[x + y]; ))
|
||||
FOR5(x, 1,
|
||||
FOR5(y, 5,
|
||||
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
||||
// Rho and pi
|
||||
uint64_t t = a[1];
|
||||
x = 0;
|
||||
REPEAT24(b[0] = a[pi[x]];
|
||||
a[pi[x]] = rol(t, rho[x]);
|
||||
t = b[0];
|
||||
x++; )
|
||||
// Chi
|
||||
FOR5(y,
|
||||
5,
|
||||
FOR5(x, 1,
|
||||
b[x] = a[y + x];)
|
||||
FOR5(x, 1,
|
||||
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
|
||||
// Iota
|
||||
a[0] ^= RC[i];
|
||||
}
|
||||
}
|
||||
|
||||
/******** The FIPS202-defined functions. ********/
|
||||
|
||||
/*** Some helper macros. ***/
|
||||
|
||||
#define _(S) do { S } while (0)
|
||||
#define FOR(i, ST, L, S) \
|
||||
_(for (size_t i = 0; i < L; i += ST) { S; })
|
||||
#define mkapply_ds(NAME, S) \
|
||||
static inline void NAME(uint8_t* dst, \
|
||||
uint8_t const* src, \
|
||||
size_t len) { \
|
||||
FOR(i, 1, len, S); \
|
||||
}
|
||||
#define mkapply_sd(NAME, S) \
|
||||
static inline void NAME(uint8_t const* src, \
|
||||
uint8_t* dst, \
|
||||
size_t len) { \
|
||||
FOR(i, 1, len, S); \
|
||||
}
|
||||
|
||||
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
|
||||
mkapply_sd(setout, dst[i] = src[i]) // setout
|
||||
|
||||
#define P keccakf
|
||||
#define Plen 200
|
||||
|
||||
// Fold P*F over the full blocks of an input.
|
||||
#define foldP(I, L, F) \
|
||||
while (L >= rate) { \
|
||||
F(a, I, rate); \
|
||||
P(a); \
|
||||
I += rate; \
|
||||
L -= rate; \
|
||||
}
|
||||
|
||||
/** The sponge-based hash construction. **/
|
||||
inline void hash(
|
||||
uint8_t* out,
|
||||
size_t outlen,
|
||||
uint8_t const* in,
|
||||
size_t inlen,
|
||||
size_t rate,
|
||||
uint8_t delim
|
||||
)
|
||||
{
|
||||
uint8_t a[Plen] = {0};
|
||||
// Absorb input.
|
||||
foldP(in, inlen, xorin);
|
||||
// Xor in the DS and pad frame.
|
||||
a[inlen] ^= delim;
|
||||
a[rate - 1] ^= 0x80;
|
||||
// Xor in the last block.
|
||||
xorin(a, in, inlen);
|
||||
// Apply P
|
||||
P(a);
|
||||
// Squeeze output.
|
||||
foldP(out, outlen, setout);
|
||||
setout(a, out, outlen);
|
||||
memset(a, 0, 200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
h256 keccak256(bytesConstRef _input)
|
||||
{
|
||||
h256 output;
|
||||
// Parameters used:
|
||||
// The 0x01 is the specific padding for keccak (sha3 uses 0x06) and
|
||||
// the way the round size (or window or whatever it was) is calculated.
|
||||
// 200 - (256 / 4) is the "rate"
|
||||
hash(output.data(), output.size, _input.data(), _input.size(), 200 - (256 / 4), 0x01);
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file SHA3.h
|
||||
* @author Gav Wood <i@gavwood.com>
|
||||
* @date 2014
|
||||
*
|
||||
* The FixedHash fixed-size "hash" container type.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/FixedHash.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
|
||||
h256 keccak256(bytesConstRef _input);
|
||||
|
||||
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
|
||||
inline h256 keccak256(bytes const& _input) { return keccak256(bytesConstRef(&_input)); }
|
||||
|
||||
/// Calculate Keccak-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
|
||||
inline h256 keccak256(std::string const& _input) { return keccak256(bytesConstRef(_input)); }
|
||||
|
||||
/// Calculate Keccak-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
|
||||
template<unsigned N> inline h256 keccak256(FixedHash<N> const& _input) { return keccak256(_input.ref()); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Simple generic result that holds a value and an optional error message.
|
||||
/// Results can be implicitly converted to and created from the type of
|
||||
/// the value they hold. The class is mainly designed for a result type of
|
||||
/// bool or pointer type. The idea is that the default constructed value of
|
||||
/// the result type is interpreted as an error value.
|
||||
///
|
||||
/// Result<bool> check()
|
||||
/// {
|
||||
/// if (false)
|
||||
/// return Result<bool>::err("Error message.")
|
||||
/// return true;
|
||||
/// }
|
||||
///
|
||||
|
||||
template <class ResultType>
|
||||
class Result
|
||||
{
|
||||
public:
|
||||
/// Constructs a result with _value and an empty message.
|
||||
/// This is meant to be called with valid results. Please use
|
||||
/// the static err() member function to signal an error.
|
||||
Result(ResultType _value): Result(_value, std::string{}) {}
|
||||
|
||||
/// Constructs a result with a default-constructed value and an
|
||||
/// error message.
|
||||
static Result<ResultType> err(std::string _message)
|
||||
{
|
||||
return Result{ResultType{}, std::move(_message)};
|
||||
}
|
||||
|
||||
/// @{
|
||||
/// @name Wrapper functions
|
||||
/// Wrapper functions that provide implicit conversions to and explicit retrieval of
|
||||
/// the value this result holds.
|
||||
operator ResultType const&() const { return m_value; }
|
||||
ResultType const& get() const { return m_value; }
|
||||
/// @}
|
||||
|
||||
/// @returns the error message (can be empty).
|
||||
std::string const& message() const { return m_message; }
|
||||
|
||||
/// Merges _other into this using the _merger
|
||||
/// and appends the error messages. Meant to be called
|
||||
/// with logical operators like logical_and, etc.
|
||||
template<typename F>
|
||||
void merge(Result<ResultType> const& _other, F _merger)
|
||||
{
|
||||
m_value = _merger(m_value, _other.get());
|
||||
m_message += _other.message();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Result(ResultType _value, std::string _message):
|
||||
m_value(std::move(_value)),
|
||||
m_message(std::move(_message))
|
||||
{}
|
||||
|
||||
ResultType m_value;
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file StringUtils.h
|
||||
* @author Balajiganapathi S <balajiganapathi.s@gmail.com>
|
||||
* @date 2017
|
||||
*
|
||||
* String routines
|
||||
*/
|
||||
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
|
||||
bool solidity::util::stringWithinDistance(string const& _str1, string const& _str2, size_t _maxDistance, size_t _lenThreshold)
|
||||
{
|
||||
if (_str1 == _str2)
|
||||
return true;
|
||||
|
||||
size_t n1 = _str1.size();
|
||||
size_t n2 = _str2.size();
|
||||
if (_lenThreshold > 0 && n1 * n2 > _lenThreshold)
|
||||
return false;
|
||||
|
||||
size_t distance = stringDistance(_str1, _str2);
|
||||
|
||||
// if distance is not greater than _maxDistance, and distance is strictly less than length of both names, they can be considered similar
|
||||
// this is to avoid irrelevant suggestions
|
||||
return distance <= _maxDistance && distance < n1 && distance < n2;
|
||||
}
|
||||
|
||||
size_t solidity::util::stringDistance(string const& _str1, string const& _str2)
|
||||
{
|
||||
size_t n1 = _str1.size();
|
||||
size_t n2 = _str2.size();
|
||||
// Optimize by storing only last 2 rows and current row. So first index is considered modulo 3
|
||||
// This is a two-dimensional array of size 3 x (n2 + 1).
|
||||
vector<size_t> dp(3 * (n2 + 1));
|
||||
|
||||
// In this dp formulation of Damerau–Levenshtein distance we are assuming that the strings are 1-based to make base case storage easier.
|
||||
// So index accesser to _name1 and _name2 have to be adjusted accordingly
|
||||
for (size_t i1 = 0; i1 <= n1; ++i1)
|
||||
for (size_t i2 = 0; i2 <= n2; ++i2)
|
||||
{
|
||||
size_t x = 0;
|
||||
if (min(i1, i2) == 0) // base case
|
||||
x = max(i1, i2);
|
||||
else
|
||||
{
|
||||
size_t left = dp[(i1 - 1) % 3 + i2 * 3];
|
||||
size_t up = dp[(i1 % 3) + (i2 - 1) * 3];
|
||||
size_t upleft = dp[((i1 - 1) % 3) + (i2 - 1) * 3];
|
||||
// deletion and insertion
|
||||
x = min(left + 1, up + 1);
|
||||
if (_str1[i1-1] == _str2[i2-1])
|
||||
// same chars, can skip
|
||||
x = min(x, upleft);
|
||||
else
|
||||
// different chars so try substitution
|
||||
x = min(x, upleft + 1);
|
||||
|
||||
// transposing
|
||||
if (i1 > 1 && i2 > 1 && _str1[i1 - 1] == _str2[i2 - 2] && _str1[i1 - 2] == _str2[i2 - 1])
|
||||
x = min(x, dp[((i1 - 2) % 3) + (i2 - 2) * 3] + 1);
|
||||
}
|
||||
dp[(i1 % 3) + i2 * 3] = x;
|
||||
}
|
||||
|
||||
return dp[(n1 % 3) + n2 * 3];
|
||||
}
|
||||
|
||||
string solidity::util::quotedAlternativesList(vector<string> const& suggestions)
|
||||
{
|
||||
vector<string> quotedSuggestions;
|
||||
|
||||
for (auto& suggestion: suggestions)
|
||||
quotedSuggestions.emplace_back("\"" + suggestion + "\"");
|
||||
|
||||
return joinHumanReadable(quotedSuggestions, ", ", " or ");
|
||||
}
|
||||
|
||||
string solidity::util::suffixedVariableNameList(string const& _baseName, size_t _startSuffix, size_t _endSuffix)
|
||||
{
|
||||
string result;
|
||||
if (_startSuffix < _endSuffix)
|
||||
{
|
||||
result = _baseName + to_string(_startSuffix++);
|
||||
while (_startSuffix < _endSuffix)
|
||||
result += ", " + _baseName + to_string(_startSuffix++);
|
||||
}
|
||||
else if (_endSuffix < _startSuffix)
|
||||
{
|
||||
result = _baseName + to_string(_endSuffix++);
|
||||
while (_endSuffix < _startSuffix)
|
||||
result = _baseName + to_string(_endSuffix++) + ", " + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file StringUtils.h
|
||||
* @author Balajiganapathi S <balajiganapathi.s@gmail.com>
|
||||
* @date 2017
|
||||
*
|
||||
* String routines
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
// Calculates the Damerau–Levenshtein distance between _str1 and _str2 and returns true if that distance is not greater than _maxDistance
|
||||
// if _lenThreshold > 0 and the product of the strings length is greater than _lenThreshold, the function will return false
|
||||
bool stringWithinDistance(std::string const& _str1, std::string const& _str2, size_t _maxDistance, size_t _lenThreshold = 0);
|
||||
// Calculates the Damerau–Levenshtein distance between _str1 and _str2
|
||||
size_t stringDistance(std::string const& _str1, std::string const& _str2);
|
||||
// Return a string having elements of suggestions as quoted, alternative suggestions. e.g. "a", "b" or "c"
|
||||
std::string quotedAlternativesList(std::vector<std::string> const& suggestions);
|
||||
|
||||
/// @returns a string containing a comma-separated list of variable names consisting of @a _baseName suffixed
|
||||
/// with increasing integers in the range [@a _startSuffix, @a _endSuffix), if @a _startSuffix < @a _endSuffix,
|
||||
/// and with decreasing integers in the range [@a _endSuffix, @a _startSuffix), if @a _endSuffix < @a _startSuffix.
|
||||
/// If @a _startSuffix == @a _endSuffix, the empty string is returned.
|
||||
std::string suffixedVariableNameList(std::string const& _baseName, size_t _startSuffix, size_t _endSuffix);
|
||||
|
||||
/// Joins collection of strings into one string with separators between, last separator can be different.
|
||||
/// @param _list collection of strings to join
|
||||
/// @param _separator defaults to ", "
|
||||
/// @param _lastSeparator (optional) will be used to separate last two strings instead of _separator
|
||||
/// @example join(vector<string>{"a", "b", "c"}, "; ", " or ") == "a; b or c"
|
||||
template<class T>
|
||||
std::string joinHumanReadable
|
||||
(
|
||||
T const& _list,
|
||||
std::string const& _separator = ", ",
|
||||
std::string const& _lastSeparator = ""
|
||||
)
|
||||
{
|
||||
auto const itEnd = end(_list);
|
||||
|
||||
std::string result;
|
||||
|
||||
for (auto it = begin(_list); it != itEnd; )
|
||||
{
|
||||
std::string element = *it;
|
||||
bool first = (it == begin(_list));
|
||||
++it;
|
||||
if (!first)
|
||||
{
|
||||
if (it == itEnd && !_lastSeparator.empty())
|
||||
result += _lastSeparator; // last iteration
|
||||
else
|
||||
result += _separator;
|
||||
}
|
||||
result += std::move(element);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Joins collection of strings just like joinHumanReadable, but prepends the separator
|
||||
/// unless the collection is empty.
|
||||
template<class T>
|
||||
std::string joinHumanReadablePrefixed
|
||||
(
|
||||
T const& _list,
|
||||
std::string const& _separator = ", ",
|
||||
std::string const& _lastSeparator = ""
|
||||
)
|
||||
{
|
||||
if (begin(_list) == end(_list))
|
||||
return {};
|
||||
else
|
||||
return _separator + joinHumanReadable(_list, _separator, _lastSeparator);
|
||||
}
|
||||
|
||||
/// Formats large numbers to be easily readable by humans.
|
||||
/// Returns decimal representation for smaller numbers; hex for large numbers.
|
||||
/// "Special" numbers, powers-of-two and powers-of-two minus 1, are returned in
|
||||
/// formulaic form like 0x01 * 2**24 - 1.
|
||||
/// @a T will typically by unsigned, u160, u256 or bigint.
|
||||
/// @param _value to be formatted
|
||||
/// @param _useTruncation if true, internal truncation is also applied,
|
||||
/// like 0x5555...{+56 more}...5555
|
||||
/// @example formatNumber((u256)0x7ffffff)
|
||||
template <class T>
|
||||
inline std::string formatNumberReadable(
|
||||
T const& _value,
|
||||
bool _useTruncation = false
|
||||
)
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed,
|
||||
"only unsigned types or bigint supported"
|
||||
); //bigint does not carry sign bit on shift
|
||||
|
||||
// smaller numbers return as decimal
|
||||
if (_value <= 0x1000000)
|
||||
return _value.str();
|
||||
|
||||
HexCase hexcase = HexCase::Mixed;
|
||||
HexPrefix prefix = HexPrefix::Add;
|
||||
|
||||
// when multiple trailing zero bytes, format as N * 2**x
|
||||
int i = 0;
|
||||
T v = _value;
|
||||
for (; (v & 0xff) == 0; v >>= 8)
|
||||
++i;
|
||||
if (i > 2)
|
||||
{
|
||||
// 0x100 yields 2**8 (N is 1 and redundant)
|
||||
if (v == 1)
|
||||
return "2**" + std::to_string(i * 8);
|
||||
return toHex(toCompactBigEndian(v), prefix, hexcase) +
|
||||
" * 2**" +
|
||||
std::to_string(i * 8);
|
||||
}
|
||||
|
||||
// when multiple trailing FF bytes, format as N * 2**x - 1
|
||||
i = 0;
|
||||
for (v = _value; (v & 0xff) == 0xff; v >>= 8)
|
||||
++i;
|
||||
if (i > 2)
|
||||
{
|
||||
// 0xFF yields 2**8 - 1 (v is 0 in that case)
|
||||
if (v == 0)
|
||||
return "2**" + std::to_string(i * 8) + " - 1";
|
||||
return toHex(toCompactBigEndian(T(v + 1)), prefix, hexcase) +
|
||||
" * 2**" + std::to_string(i * 8) +
|
||||
" - 1";
|
||||
}
|
||||
|
||||
std::string str = toHex(toCompactBigEndian(_value), prefix, hexcase);
|
||||
if (_useTruncation)
|
||||
{
|
||||
// return as interior-truncated hex.
|
||||
int len = str.size();
|
||||
|
||||
if (len < 24)
|
||||
return str;
|
||||
|
||||
int const initialChars = (prefix == HexPrefix::Add) ? 6 : 4;
|
||||
int const finalChars = 4;
|
||||
int numSkipped = len - initialChars - finalChars;
|
||||
|
||||
return str.substr(0, initialChars) +
|
||||
"...{+" +
|
||||
std::to_string(numSkipped) +
|
||||
" more}..." +
|
||||
str.substr(len-finalChars, len);
|
||||
}
|
||||
|
||||
// otherwise, show whole value.
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file SwarmHash.cpp
|
||||
*/
|
||||
|
||||
#include <libsolutil/SwarmHash.h>
|
||||
|
||||
#include <libsolutil/Keccak256.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bytes toLittleEndian(size_t _size)
|
||||
{
|
||||
bytes encoded(8);
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
encoded[i] = (_size >> (8 * i)) & 0xff;
|
||||
return encoded;
|
||||
}
|
||||
|
||||
h256 swarmHashSimple(bytesConstRef _data, size_t _size)
|
||||
{
|
||||
return keccak256(toLittleEndian(_size) + _data.toBytes());
|
||||
}
|
||||
|
||||
h256 swarmHashIntermediate(string const& _input, size_t _offset, size_t _length)
|
||||
{
|
||||
bytesConstRef ref;
|
||||
bytes innerNodes;
|
||||
if (_length <= 0x1000)
|
||||
ref = bytesConstRef(_input).cropped(_offset, _length);
|
||||
else
|
||||
{
|
||||
size_t maxRepresentedSize = 0x1000;
|
||||
while (maxRepresentedSize * (0x1000 / 32) < _length)
|
||||
maxRepresentedSize *= (0x1000 / 32);
|
||||
for (size_t i = 0; i < _length; i += maxRepresentedSize)
|
||||
{
|
||||
size_t size = std::min(maxRepresentedSize, _length - i);
|
||||
innerNodes += swarmHashIntermediate(_input, _offset + i, size).asBytes();
|
||||
}
|
||||
ref = bytesConstRef(&innerNodes);
|
||||
}
|
||||
return swarmHashSimple(ref, _length);
|
||||
}
|
||||
|
||||
h256 bmtHash(bytesConstRef _data)
|
||||
{
|
||||
if (_data.size() <= 64)
|
||||
return keccak256(_data);
|
||||
|
||||
size_t midPoint = _data.size() / 2;
|
||||
return keccak256(
|
||||
bmtHash(_data.cropped(0, midPoint)).asBytes() +
|
||||
bmtHash(_data.cropped(midPoint)).asBytes()
|
||||
);
|
||||
}
|
||||
|
||||
h256 chunkHash(bytesConstRef const _data, bool _forceHigherLevel = false)
|
||||
{
|
||||
bytes dataToHash;
|
||||
if (_data.size() < 0x1000)
|
||||
dataToHash = _data.toBytes();
|
||||
else if (_data.size() == 0x1000 && !_forceHigherLevel)
|
||||
dataToHash = _data.toBytes();
|
||||
else
|
||||
{
|
||||
size_t maxRepresentedSize = 0x1000;
|
||||
while (maxRepresentedSize * (0x1000 / 32) < _data.size())
|
||||
maxRepresentedSize *= (0x1000 / 32);
|
||||
// If remaining size is 0x1000, but maxRepresentedSize is not,
|
||||
// we have to still do one level of the chunk hashes.
|
||||
bool forceHigher = maxRepresentedSize > 0x1000;
|
||||
for (size_t i = 0; i < _data.size(); i += maxRepresentedSize)
|
||||
{
|
||||
size_t size = std::min(maxRepresentedSize, _data.size() - i);
|
||||
dataToHash += chunkHash(_data.cropped(i, size), forceHigher).asBytes();
|
||||
}
|
||||
}
|
||||
|
||||
dataToHash.resize(0x1000, 0);
|
||||
return keccak256(toLittleEndian(_data.size()) + bmtHash(&dataToHash).asBytes());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
h256 solidity::util::bzzr0Hash(string const& _input)
|
||||
{
|
||||
return swarmHashIntermediate(_input, 0, _input.size());
|
||||
}
|
||||
|
||||
|
||||
h256 solidity::util::bzzr1Hash(bytes const& _input)
|
||||
{
|
||||
if (_input.empty())
|
||||
return h256{};
|
||||
return chunkHash(&_input);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file SwarmHash.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/FixedHash.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Compute the "swarm hash" of @a _input (OLD 0x1000-section version)
|
||||
h256 bzzr0Hash(std::string const& _input);
|
||||
|
||||
/// Compute the "bzz hash" of @a _input (the NEW binary / BMT version)
|
||||
h256 bzzr1Hash(bytes const& _input);
|
||||
|
||||
inline h256 bzzr1Hash(std::string const& _input)
|
||||
{
|
||||
return bzzr1Hash(asBytes(_input));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file UTF8.cpp
|
||||
* @author Alex Beregszaszi
|
||||
* @date 2016
|
||||
*
|
||||
* UTF-8 related helpers
|
||||
*/
|
||||
|
||||
#include <libsolutil/UTF8.h>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
/// Validate byte sequence against Unicode chapter 3 Table 3-7.
|
||||
bool isWellFormed(unsigned char byte1, unsigned char byte2)
|
||||
{
|
||||
if (byte1 == 0xc0 || byte1 == 0xc1)
|
||||
return false;
|
||||
else if (byte1 >= 0xc2 && byte1 <= 0xdf)
|
||||
return true;
|
||||
else if (byte1 == 0xe0)
|
||||
{
|
||||
if (byte2 < 0xa0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else if (byte1 >= 0xe1 && byte1 <= 0xec)
|
||||
return true;
|
||||
else if (byte1 == 0xed)
|
||||
{
|
||||
if (byte2 > 0x9f)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else if (byte1 == 0xee || byte1 == 0xef)
|
||||
return true;
|
||||
else if (byte1 == 0xf0)
|
||||
{
|
||||
if (byte2 < 0x90)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else if (byte1 >= 0xf1 && byte1 <= 0xf3)
|
||||
return true;
|
||||
else if (byte1 == 0xf4)
|
||||
{
|
||||
if (byte2 > 0x8f)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
/// 0xf5 .. 0xf7 is disallowed
|
||||
/// Technically anything below 0xc0 or above 0xf7 is
|
||||
/// not possible to encode using Table 3-6 anyway.
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool validateUTF8(unsigned char const* _input, size_t _length, size_t& _invalidPosition)
|
||||
{
|
||||
bool valid = true;
|
||||
size_t i = 0;
|
||||
|
||||
for (; i < _length; i++)
|
||||
{
|
||||
// Check for Unicode Chapter 3 Table 3-6 conformity.
|
||||
if (_input[i] < 0x80)
|
||||
continue;
|
||||
|
||||
size_t count = 0;
|
||||
if (_input[i] >= 0xc0 && _input[i] <= 0xdf)
|
||||
count = 1;
|
||||
else if (_input[i] >= 0xe0 && _input[i] <= 0xef)
|
||||
count = 2;
|
||||
else if (_input[i] >= 0xf0 && _input[i] <= 0xf7)
|
||||
count = 3;
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((i + count) >= _length)
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < count; j++)
|
||||
{
|
||||
i++;
|
||||
if ((_input[i] & 0xc0) != 0x80)
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for Unicode Chapter 3 Table 3-7 conformity.
|
||||
if ((j == 0) && !isWellFormed(_input[i - 1], _input[i]))
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valid)
|
||||
return true;
|
||||
|
||||
_invalidPosition = i;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validateUTF8(std::string const& _input, size_t& _invalidPosition)
|
||||
{
|
||||
return validateUTF8(reinterpret_cast<unsigned char const*>(_input.c_str()), _input.length(), _invalidPosition);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file UTF8.h
|
||||
* @author Alex Beregszaszi
|
||||
* @date 2016
|
||||
*
|
||||
* UTF-8 related helpers
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/// Validate an input for UTF8 encoding
|
||||
/// @returns false if it is invalid and the first invalid position in invalidPosition
|
||||
bool validateUTF8(std::string const& _input, size_t& _invalidPosition);
|
||||
|
||||
inline bool validateUTF8(std::string const& _input)
|
||||
{
|
||||
size_t invalidPos;
|
||||
return validateUTF8(_input, invalidPos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Visitor templates.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/**
|
||||
* Generic visitor used as follows:
|
||||
* std::visit(GenericVisitor{
|
||||
* [](Class1& _c) { _c.f(); },
|
||||
* [](Class2& _c) { _c.g(); }
|
||||
* }, variant);
|
||||
* This one does not have a fallback and will fail at
|
||||
* compile-time if you do not specify all variants.
|
||||
*
|
||||
* Fallback with no return (it will not fail if you do not specify all variants):
|
||||
* std::visit(GenericVisitor{
|
||||
* VisitorFallback<>{},
|
||||
* [](Class1& _c) { _c.f(); },
|
||||
* [](Class2& _c) { _c.g(); }
|
||||
* }, variant);
|
||||
*
|
||||
* Fallback with return type R (the fallback returns `R{}`:
|
||||
* std::visit(GenericVisitor{
|
||||
* VisitorFallback<R>{},
|
||||
* [](Class1& _c) { _c.f(); },
|
||||
* [](Class2& _c) { _c.g(); }
|
||||
* }, variant);
|
||||
*/
|
||||
|
||||
template <typename...> struct VisitorFallback;
|
||||
|
||||
template <typename R>
|
||||
struct VisitorFallback<R> { template<typename T> R operator()(T&&) const { return {}; } };
|
||||
|
||||
template<>
|
||||
struct VisitorFallback<> { template<typename T> void operator()(T&&) const {} };
|
||||
|
||||
template <typename... Visitors> struct GenericVisitor: Visitors... { using Visitors::operator()...; };
|
||||
template <typename... Visitors> GenericVisitor(Visitors...) -> GenericVisitor<Visitors...>;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file Whiskers.cpp
|
||||
* @author Chris <chis@ethereum.org>
|
||||
* @date 2017
|
||||
*
|
||||
* Moustache-like templates.
|
||||
*/
|
||||
|
||||
#include <libsolutil/Whiskers.h>
|
||||
|
||||
#include <libsolutil/Assertions.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
|
||||
Whiskers::Whiskers(string _template):
|
||||
m_template(move(_template))
|
||||
{
|
||||
}
|
||||
|
||||
Whiskers& Whiskers::operator()(string _parameter, string _value)
|
||||
{
|
||||
checkParameterValid(_parameter);
|
||||
checkParameterUnknown(_parameter);
|
||||
m_parameters[move(_parameter)] = move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Whiskers& Whiskers::operator()(string _parameter, bool _value)
|
||||
{
|
||||
checkParameterValid(_parameter);
|
||||
checkParameterUnknown(_parameter);
|
||||
m_conditions[move(_parameter)] = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Whiskers& Whiskers::operator()(
|
||||
string _listParameter,
|
||||
vector<map<string, string>> _values
|
||||
)
|
||||
{
|
||||
checkParameterValid(_listParameter);
|
||||
checkParameterUnknown(_listParameter);
|
||||
for (auto const& element: _values)
|
||||
for (auto const& val: element)
|
||||
checkParameterValid(val.first);
|
||||
m_listParameters[move(_listParameter)] = move(_values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string Whiskers::render() const
|
||||
{
|
||||
return replace(m_template, m_parameters, m_conditions, m_listParameters);
|
||||
}
|
||||
|
||||
void Whiskers::checkParameterValid(string const& _parameter) const
|
||||
{
|
||||
static regex validParam("^" + paramRegex() + "$");
|
||||
assertThrow(
|
||||
regex_match(_parameter, validParam),
|
||||
WhiskersError,
|
||||
"Parameter" + _parameter + " contains invalid characters."
|
||||
);
|
||||
}
|
||||
|
||||
void Whiskers::checkParameterUnknown(string const& _parameter) const
|
||||
{
|
||||
assertThrow(
|
||||
!m_parameters.count(_parameter),
|
||||
WhiskersError,
|
||||
_parameter + " already set as value parameter."
|
||||
);
|
||||
assertThrow(
|
||||
!m_conditions.count(_parameter),
|
||||
WhiskersError,
|
||||
_parameter + " already set as condition parameter."
|
||||
);
|
||||
assertThrow(
|
||||
!m_listParameters.count(_parameter),
|
||||
WhiskersError,
|
||||
_parameter + " already set as list parameter."
|
||||
);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<class ReplaceCallback>
|
||||
string regex_replace(
|
||||
string const& _source,
|
||||
regex const& _pattern,
|
||||
ReplaceCallback _replace,
|
||||
regex_constants::match_flag_type _flags = regex_constants::match_default
|
||||
)
|
||||
{
|
||||
sregex_iterator curMatch(_source.begin(), _source.end(), _pattern, _flags);
|
||||
sregex_iterator matchEnd;
|
||||
string::const_iterator lastMatchedPos(_source.cbegin());
|
||||
string result;
|
||||
while (curMatch != matchEnd)
|
||||
{
|
||||
result.append(curMatch->prefix().first, curMatch->prefix().second);
|
||||
result.append(_replace(*curMatch));
|
||||
lastMatchedPos = (*curMatch)[0].second;
|
||||
++curMatch;
|
||||
}
|
||||
result.append(lastMatchedPos, _source.cend());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
string Whiskers::replace(
|
||||
string const& _template,
|
||||
StringMap const& _parameters,
|
||||
map<string, bool> const& _conditions,
|
||||
map<string, vector<StringMap>> const& _listParameters
|
||||
)
|
||||
{
|
||||
static regex listOrTag("<(" + paramRegex() + ")>|<#(" + paramRegex() + ")>((?:.|\\r|\\n)*?)</\\2>|<\\?(" + paramRegex() + ")>((?:.|\\r|\\n)*?)(<!\\4>((?:.|\\r|\\n)*?))?</\\4>");
|
||||
return regex_replace(_template, listOrTag, [&](match_results<string::const_iterator> _match) -> string
|
||||
{
|
||||
string tagName(_match[1]);
|
||||
string listName(_match[2]);
|
||||
string conditionName(_match[4]);
|
||||
if (!tagName.empty())
|
||||
{
|
||||
assertThrow(
|
||||
_parameters.count(tagName),
|
||||
WhiskersError,
|
||||
"Value for tag " + tagName + " not provided.\n" +
|
||||
"Template:\n" +
|
||||
_template
|
||||
);
|
||||
return _parameters.at(tagName);
|
||||
}
|
||||
else if (!listName.empty())
|
||||
{
|
||||
string templ(_match[3]);
|
||||
assertThrow(
|
||||
_listParameters.count(listName),
|
||||
WhiskersError, "List parameter " + listName + " not set."
|
||||
);
|
||||
string replacement;
|
||||
for (auto const& parameters: _listParameters.at(listName))
|
||||
replacement += replace(templ, joinMaps(_parameters, parameters), _conditions);
|
||||
return replacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
assertThrow(!conditionName.empty(), WhiskersError, "");
|
||||
assertThrow(
|
||||
_conditions.count(conditionName),
|
||||
WhiskersError, "Condition parameter " + conditionName + " not set."
|
||||
);
|
||||
return replace(
|
||||
_conditions.at(conditionName) ? _match[5] : _match[7],
|
||||
_parameters,
|
||||
_conditions,
|
||||
_listParameters
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Whiskers::StringMap Whiskers::joinMaps(
|
||||
Whiskers::StringMap const& _a,
|
||||
Whiskers::StringMap const& _b
|
||||
)
|
||||
{
|
||||
Whiskers::StringMap ret = _a;
|
||||
for (auto const& x: _b)
|
||||
assertThrow(
|
||||
ret.insert(x).second,
|
||||
WhiskersError,
|
||||
"Parameter collision"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file Whiskers.h
|
||||
* @author Chris <chis@ethereum.org>
|
||||
* @date 2017
|
||||
*
|
||||
* Moustache-like templates.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
DEV_SIMPLE_EXCEPTION(WhiskersError);
|
||||
|
||||
/**
|
||||
* Moustache-like templates.
|
||||
*
|
||||
* Usage:
|
||||
* std::vector<std::map<std::string, std::string>> listValues(2);
|
||||
* listValues[0]["k"] = "key1";
|
||||
* listValues[0]["v"] = "value1";
|
||||
* listValues[1]["k"] = "key2";
|
||||
* listValues[1]["v"] = "value2";
|
||||
* auto s = Whiskers("<?c><p1><!c>y</c>\n<#list><k> -> <v>\n</list>")
|
||||
* ("p1", "HEAD")
|
||||
* ("c", true)
|
||||
* ("list", listValues)
|
||||
* .render();
|
||||
*
|
||||
* results in s == "HEAD\nkey1 -> value1\nkey2 -> value2\n"
|
||||
*
|
||||
* Note that lists cannot themselves contain lists - this would be a future feature.
|
||||
*
|
||||
* The elements are:
|
||||
* - Regular parameter: <name>
|
||||
* just replaced
|
||||
* - Condition parameter: <?name>...<!name>...</name>, where "<!name>" is optional
|
||||
* replaced (and recursively expanded) by the first part if the condition is true
|
||||
* and by the second (or empty string if missing) if the condition is false
|
||||
* - List parameter: <#list>...</list>
|
||||
* The part between the tags is repeated as often as values are provided
|
||||
* in the mapping. Each list element can have its own parameter -> value mapping.
|
||||
*/
|
||||
class Whiskers
|
||||
{
|
||||
public:
|
||||
using StringMap = std::map<std::string, std::string>;
|
||||
using StringListMap = std::map<std::string, std::vector<StringMap>>;
|
||||
|
||||
explicit Whiskers(std::string _template);
|
||||
|
||||
/// Sets a single regular parameter, <paramName>.
|
||||
Whiskers& operator()(std::string _parameter, std::string _value);
|
||||
Whiskers& operator()(std::string _parameter, char const* _value) { return (*this)(_parameter, std::string{_value}); }
|
||||
/// Sets a condition parameter, <?paramName>...<!paramName>...</paramName>
|
||||
Whiskers& operator()(std::string _parameter, bool _value);
|
||||
/// Sets a list parameter, <#listName> </listName>.
|
||||
Whiskers& operator()(
|
||||
std::string _listParameter,
|
||||
std::vector<StringMap> _values
|
||||
);
|
||||
|
||||
std::string render() const;
|
||||
|
||||
private:
|
||||
// Prevent implicit cast to bool
|
||||
Whiskers& operator()(std::string _parameter, long long);
|
||||
void checkParameterValid(std::string const& _parameter) const;
|
||||
void checkParameterUnknown(std::string const& _parameter) const;
|
||||
|
||||
static std::string replace(
|
||||
std::string const& _template,
|
||||
StringMap const& _parameters,
|
||||
std::map<std::string, bool> const& _conditions,
|
||||
StringListMap const& _listParameters = StringListMap()
|
||||
);
|
||||
|
||||
static std::string paramRegex() { return "[a-zA-Z0-9_$-]+"; }
|
||||
|
||||
/// Joins the two maps throwing an exception if two keys are equal.
|
||||
static StringMap joinMaps(StringMap const& _a, StringMap const& _b);
|
||||
|
||||
std::string m_template;
|
||||
StringMap m_parameters;
|
||||
std::map<std::string, bool> m_conditions;
|
||||
StringListMap m_listParameters;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2014 okdshin
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
//picosha2:20140213
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace picosha2
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline uint8_t mask_8bit(uint8_t x)
|
||||
{
|
||||
return x & 0xff;
|
||||
}
|
||||
|
||||
inline uint32_t mask_32bit(uint32_t x)
|
||||
{
|
||||
return x & 0xffffffff;
|
||||
}
|
||||
|
||||
static uint32_t const add_constant[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
static uint32_t const initial_message_digest[8] = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z)
|
||||
{
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
|
||||
{
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
inline uint32_t rotr(uint32_t x, std::size_t n)
|
||||
{
|
||||
assert(n < 32);
|
||||
return mask_32bit((x >> n) | (x << (32 - n)));
|
||||
}
|
||||
|
||||
inline uint32_t bsig0(uint32_t x)
|
||||
{
|
||||
return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
|
||||
}
|
||||
|
||||
inline uint32_t bsig1(uint32_t x)
|
||||
{
|
||||
return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
|
||||
}
|
||||
|
||||
inline uint32_t shr(uint32_t x, std::size_t n)
|
||||
{
|
||||
assert(n < 32);
|
||||
return x >> n;
|
||||
}
|
||||
|
||||
inline uint32_t ssig0(uint32_t x)
|
||||
{
|
||||
return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3);
|
||||
}
|
||||
|
||||
inline uint32_t ssig1(uint32_t x)
|
||||
{
|
||||
return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10);
|
||||
}
|
||||
|
||||
template<typename RaIter1, typename RaIter2>
|
||||
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last)
|
||||
{
|
||||
(void)last; // FIXME: check this is valid
|
||||
uint32_t w[64];
|
||||
std::fill(w, w+64, 0);
|
||||
for (std::size_t i = 0; i < 16; ++i)
|
||||
w[i] = (static_cast<uint32_t>(mask_8bit(*(first + i * 4))) << 24)
|
||||
| (static_cast<uint32_t>(mask_8bit(*(first + i * 4 + 1))) << 16)
|
||||
| (static_cast<uint32_t>(mask_8bit(*(first + i * 4 + 2))) << 8)
|
||||
| (static_cast<uint32_t>(mask_8bit(*(first + i * 4 + 3))));
|
||||
for (std::size_t i = 16; i < 64; ++i)
|
||||
w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]);
|
||||
|
||||
uint32_t a = *message_digest;
|
||||
uint32_t b = *(message_digest + 1);
|
||||
uint32_t c = *(message_digest + 2);
|
||||
uint32_t d = *(message_digest + 3);
|
||||
uint32_t e = *(message_digest + 4);
|
||||
uint32_t f = *(message_digest + 5);
|
||||
uint32_t g = *(message_digest + 6);
|
||||
uint32_t h = *(message_digest + 7);
|
||||
|
||||
for (std::size_t i = 0; i < 64; ++i)
|
||||
{
|
||||
uint32_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i];
|
||||
uint32_t temp2 = bsig0(a)+maj(a,b,c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = mask_32bit(d+temp1);
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = mask_32bit(temp1+temp2);
|
||||
}
|
||||
*message_digest += a;
|
||||
*(message_digest+1) += b;
|
||||
*(message_digest+2) += c;
|
||||
*(message_digest+3) += d;
|
||||
*(message_digest+4) += e;
|
||||
*(message_digest+5) += f;
|
||||
*(message_digest+6) += g;
|
||||
*(message_digest+7) += h;
|
||||
for (std::size_t i = 0; i < 8; ++i)
|
||||
*(message_digest+i) = mask_32bit(*(message_digest+i));
|
||||
}
|
||||
|
||||
}//namespace detail
|
||||
|
||||
class hash256_one_by_one
|
||||
{
|
||||
public:
|
||||
hash256_one_by_one()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
buffer_.clear();
|
||||
std::fill(data_length_digits_, data_length_digits_ + 4, 0);
|
||||
std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_);
|
||||
}
|
||||
|
||||
template<typename RaIter>
|
||||
void process(RaIter first, RaIter last)
|
||||
{
|
||||
add_to_data_length(std::distance(first, last));
|
||||
std::copy(first, last, std::back_inserter(buffer_));
|
||||
std::size_t i = 0;
|
||||
for (;i + 64 <= buffer_.size(); i+=64)
|
||||
detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64);
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin()+i);
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
uint8_t temp[64];
|
||||
std::fill(temp, temp+64, 0);
|
||||
std::size_t remains = buffer_.size();
|
||||
std::copy(buffer_.begin(), buffer_.end(), temp);
|
||||
temp[remains] = 0x80;
|
||||
|
||||
if (remains > 55)
|
||||
{
|
||||
std::fill(temp+remains+1, temp+64, 0);
|
||||
detail::hash256_block(h_, temp, temp+64);
|
||||
std::fill(temp, temp+64-4, 0);
|
||||
}
|
||||
else
|
||||
std::fill(temp+remains+1, temp+64-4, 0);
|
||||
|
||||
write_data_bit_length(&(temp[56]));
|
||||
detail::hash256_block(h_, temp, temp+64);
|
||||
}
|
||||
|
||||
template<typename OutIter>
|
||||
void get_hash_bytes(OutIter first, OutIter last) const
|
||||
{
|
||||
for (uint32_t const* iter = h_; iter != h_ + 8; ++iter)
|
||||
for (std::size_t i = 0; i < 4 && first != last; ++i)
|
||||
*(first++) = detail::mask_8bit(static_cast<uint8_t>(*iter >> (24 - 8 * i)));
|
||||
}
|
||||
|
||||
private:
|
||||
void add_to_data_length(uint32_t n)
|
||||
{
|
||||
uint32_t carry = 0;
|
||||
data_length_digits_[0] += n;
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
data_length_digits_[i] += carry;
|
||||
if (data_length_digits_[i] >= 65536u)
|
||||
{
|
||||
carry = data_length_digits_[i] >> 16;
|
||||
data_length_digits_[i] &= 65535u;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
void write_data_bit_length(uint8_t* begin)
|
||||
{
|
||||
uint32_t data_bit_length_digits[4];
|
||||
std::copy(
|
||||
data_length_digits_, data_length_digits_ + 4,
|
||||
data_bit_length_digits
|
||||
);
|
||||
|
||||
// convert byte length to bit length (multiply 8 or shift 3 times left)
|
||||
uint32_t carry = 0;
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
uint32_t before_val = data_bit_length_digits[i];
|
||||
data_bit_length_digits[i] <<= 3;
|
||||
data_bit_length_digits[i] |= carry;
|
||||
data_bit_length_digits[i] &= 65535u;
|
||||
carry = (before_val >> (16-3)) & 65535u;
|
||||
}
|
||||
|
||||
// write data_bit_length
|
||||
for (int i = 3; i >= 0; --i)
|
||||
{
|
||||
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i] >> 8);
|
||||
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i]);
|
||||
}
|
||||
}
|
||||
std::vector<uint8_t> buffer_;
|
||||
uint32_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer)
|
||||
uint32_t h_[8];
|
||||
};
|
||||
|
||||
template<typename RaIter, typename OutIter>
|
||||
void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2)
|
||||
{
|
||||
hash256_one_by_one hasher;
|
||||
//hasher.init();
|
||||
hasher.process(first, last);
|
||||
hasher.finish();
|
||||
hasher.get_hash_bytes(first2, last2);
|
||||
}
|
||||
|
||||
template <typename RaContainer>
|
||||
std::vector<uint8_t> hash256(RaContainer const& _src)
|
||||
{
|
||||
std::vector<uint8_t> ret(32);
|
||||
hash256(_src.begin(), _src.end(), ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
}//namespace picosha2
|
||||
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning(disable:597) // will not be called for implicit or explicit conversions
|
||||
#endif
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
|
||||
/**
|
||||
* A modifiable reference to an existing object or vector in memory.
|
||||
*/
|
||||
template <class _T>
|
||||
class vector_ref
|
||||
{
|
||||
public:
|
||||
using value_type = _T;
|
||||
using element_type = _T;
|
||||
using mutable_value_type = typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type;
|
||||
using string_type = typename std::conditional<std::is_const<_T>::value, std::string const, std::string>::type;
|
||||
using vector_type = typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const, std::vector<_T>>::type;
|
||||
using iterator = _T*;
|
||||
using const_iterator = _T const*;
|
||||
|
||||
static_assert(std::is_pod<value_type>::value, "vector_ref can only be used with PODs due to its low-level treatment of data.");
|
||||
|
||||
vector_ref(): m_data(nullptr), m_count(0) {}
|
||||
/// Creates a new vector_ref to point to @a _count elements starting at @a _data.
|
||||
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
|
||||
/// Creates a new vector_ref pointing to the data part of a string (given as pointer).
|
||||
vector_ref(string_type* _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {}
|
||||
/// Creates a new vector_ref pointing to the data part of a string (given as reference).
|
||||
vector_ref(string_type& _data): vector_ref(&_data) {}
|
||||
/// Creates a new vector_ref pointing to the data part of a vector (given as pointer).
|
||||
vector_ref(vector_type* _data): m_data(_data->data()), m_count(_data->size()) {}
|
||||
explicit operator bool() const { return m_data && m_count; }
|
||||
|
||||
std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); }
|
||||
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); }
|
||||
|
||||
template <class _T2> explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); }
|
||||
operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); }
|
||||
|
||||
_T* data() const { return m_data; }
|
||||
/// @returns the number of elements referenced (not necessarily number of bytes).
|
||||
size_t size() const { return m_count; }
|
||||
bool empty() const { return !m_count; }
|
||||
/// @returns a new vector_ref which is a shifted and shortened view of the original data.
|
||||
/// If this goes out of bounds in any way, returns an empty vector_ref.
|
||||
/// If @a _count is ~size_t(0), extends the view to the end of the data.
|
||||
vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin <= m_count && _count <= m_count && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); }
|
||||
/// @returns a new vector_ref which is a shifted view of the original data (not going beyond it).
|
||||
vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); }
|
||||
|
||||
_T* begin() { return m_data; }
|
||||
_T* end() { return m_data + m_count; }
|
||||
_T const* begin() const { return m_data; }
|
||||
_T const* end() const { return m_data + m_count; }
|
||||
|
||||
_T& operator[](size_t _i) { assert(m_data); assert(_i < m_count); return m_data[_i]; }
|
||||
_T const& operator[](size_t _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; }
|
||||
|
||||
bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; }
|
||||
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); }
|
||||
|
||||
void reset() { m_data = nullptr; m_count = 0; }
|
||||
|
||||
private:
|
||||
_T* m_data = nullptr;
|
||||
size_t m_count = 0;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user