diff --git a/RLP.h b/RLP.h index e09514f93..8131a9473 100644 --- a/RLP.h +++ b/RLP.h @@ -25,6 +25,9 @@ public: /// Construct a node of value given in the bytes. explicit RLP(fConstBytes _d): m_data(_d) {} + /// Construct a node of value given in the bytes. + explicit RLP(bytes const& _d): m_data(const_cast(&_d)) {} // a bit horrible, but we know we won't be altering the data. TODO: allow vector const* to be passed to foreign. + /// Construct a node to read RLP data in the bytes given. RLP(byte const* _b, uint _s): m_data(fConstBytes(_b, _s)) {} @@ -64,6 +67,26 @@ public: /// @returns the number of characters in the string, or zero if it isn't a string. uint stringSize() const { return isString() ? items() : 0; } + bool operator==(char const* _s) const { return isString() && toString() == _s; } + bool operator==(std::string const& _s) const { return isString() && toString() == _s; } + bool operator==(uint const& _i) const { return toSlimInt() == _i; } + bool operator==(u256 const& _i) const { return toFatInt() == _i; } + bool operator==(bigint const& _i) const { return toBigInt() == _i; } + RLP operator[](uint _i) const + { + if (!isList() || itemCount() <= _i) + return RLP(); + fConstBytes d = payload(); + for (uint64_t i = 0; i < _i; ++i, d = d.cropped(RLP(d).size())) {} + return RLP(d); + } + + explicit operator std::string() const { return toString(); } + explicit operator RLPs() const { return toList(); } + explicit operator uint() const { return toSlimInt(); } + explicit operator u256() const { return toFatInt(); } + explicit operator bigint() const { return toBigInt(); } + std::string toString() const { if (!isString()) @@ -78,9 +101,10 @@ public: if (isDirectValueInt()) return m_data[0]; _T ret = 0; - auto s = intSize(); + auto s = intSize() - intLengthSize(); + uint o = intLengthSize() + 1; for (uint i = 0; i < s; ++i) - ret = (ret << 8) | m_data[i + 1]; + ret = (ret << 8) | m_data[i + o]; return ret; } @@ -174,7 +198,7 @@ public: else pushCount(_s.size(), 0x40); uint os = m_out.size(); - m_out.resize(m_out.size() + _s.size()); + m_out.resize(os + _s.size()); memcpy(m_out.data() + os, _s.data(), _s.size()); } @@ -189,10 +213,12 @@ public: RLPStream operator<<(uint _i) { append(_i); return *this; } RLPStream operator<<(u256 _i) { append(_i); return *this; } RLPStream operator<<(bigint _i) { append(_i); return *this; } + RLPStream operator<<(char const* _s) { append(std::string(_s)); return *this; } RLPStream operator<<(std::string const& _s) { append(_s); return *this; } RLPStream operator<<(RLPList _l) { appendList(_l.count); return *this; } bytes const& out() const { return m_out; } + std::string str() const { return std::string((char const*)m_out.data(), (char const*)(m_out.data() + m_out.size())); } private: void appendNumeric(uint _i) @@ -203,8 +229,7 @@ private: { auto br = bytesRequired(_i); m_out.push_back(br + 0x17); // max 8 bytes. - for (int i = br - 1; i >= 0; --i) - m_out.push_back((_i >> i) & 0xff); + pushInt(_i, br); } } @@ -216,8 +241,7 @@ private: { auto br = bytesRequired(_i); m_out.push_back(br + 0x17); // max 8 bytes. - for (int i = br - 1; i >= 0; --i) - m_out.push_back((byte)(_i >> i)); + pushInt(_i, br); } } @@ -234,20 +258,25 @@ private: { auto brbr = bytesRequired(br); m_out.push_back(0x37 + brbr); - for (int i = brbr - 1; i >= 0; --i) - m_out.push_back((br >> i) & 0xff); - } - for (uint i = 0; i < br; ++i) - { - bigint u = (_i >> (br - 1 - i)); - m_out.push_back((uint)u); + pushInt(br, brbr); } + pushInt(_i, br); } } + template void pushInt(_T _i, uint _br) + { + m_out.resize(m_out.size() + _br); + byte* b = &m_out.back(); + for (; _i; _i >>= 8) + *(b--) = (byte)_i; + } + void pushCount(uint _count, byte _base) { - m_out.push_back(bytesRequired(_count) + 0x37 + _base); // max 8 bytes. + auto br = bytesRequired(_count); + m_out.push_back(br + 0x37 + _base); // max 8 bytes. + pushInt(_count, br); } template static uint bytesRequired(_T _i) diff --git a/main.cpp b/main.cpp index 04f939777..0a81c3b73 100644 --- a/main.cpp +++ b/main.cpp @@ -12,35 +12,74 @@ std::string asHex(std::string const& _data) return ret.str(); } +std::string asHex(bytes const& _data) +{ + std::ostringstream ret; + for (auto i: _data) + ret << hex << setfill('0') << setw(2) << (int)i; + return ret.str(); +} + +template void rlpListAux(RLPStream& _out, _T _t) +{ + _out << _t; +} + +template void rlpListAux(RLPStream& _out, _T _t, _Ts ... _ts) +{ + _out << _t; + rlpListAux(_out, _ts...); +} + +template std::string rlp(_T _t) +{ + RLPStream out; + out << _t; + return out.str(); +} + +template std::string rlpList(_Ts ... _ts) +{ + RLPStream out; + out << RLPList(sizeof ...(_Ts)); + rlpListAux(out, _ts...); + return out.str(); +} + int main() { // int of value 15 - assert(toString(RLP("\x0f")) == "15"); - - // 2-item list - assert(toString(RLP("\x43""dog")) == "\"dog\""); + assert(RLP("\x0f") == 15); + assert(rlp(15) == "\x0f"); // 3-character string - assert(toString(RLP("\x82\x0f\x43""dog")) == "[ 15, \"dog\" ]"); + assert(RLP("\x43""dog") == "dog"); + assert(rlp("dog") == "\x43""dog"); + + // 2-item list + RLP twoItemList("\x82\x0f\x43""dog"); + assert(twoItemList.itemCount() == 2 && twoItemList[0] == 15 && twoItemList[1] == "dog"); + assert(rlpList(15, "dog") == "\x82\x0f\x43""dog"); // 1-byte (8-bit) int - assert(toString(RLP("\x18\x45")) == "69"); + assert(RLP("\x18\x45") == 69); + assert(rlp(69) == "\x18\x45"); // 2-byte (16-bit) int - assert(toString(RLP("\x19\x01\x01")) == "257"); + assert(RLP("\x19\x01\x01") == 257); + assert(rlp(257) == "\x19\x01\x01"); // 32-byte (256-bit) int - ostringstream o1; - o1 << hex << RLP("\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"); - assert(o1.str() == "100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + assert(RLP("\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")); + assert(rlp(bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) == "\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"); // 33-byte (264-bit) int - ostringstream o2; - o2 << hex << RLP("\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"); - assert(o2.str() == "2120100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + assert(RLP("\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")); + assert(rlp(bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")) == "\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"); // 56-character string. - assert(toString(RLP("\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit")) == "\"Lorem ipsum dolor sit amet, consectetur adipisicing elit\""); + assert(RLP("\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit"); + assert(rlp("Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit"); /* * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1