mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add tiny CBOR parser
This commit is contained in:
parent
12f34c8229
commit
61220eb3e0
@ -21,6 +21,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <libdevcore/Assertions.h>
|
||||
#include <libdevcore/CommonData.h>
|
||||
#include <libdevcore/JSON.h>
|
||||
#include <test/Metadata.h>
|
||||
|
||||
@ -59,6 +61,116 @@ string bytecodeSansMetadata(string const& _bytecode)
|
||||
return toHex(bytecodeSansMetadata(fromHex(_bytecode, WhenError::Throw)));
|
||||
}
|
||||
|
||||
DEV_SIMPLE_EXCEPTION(CBORException);
|
||||
|
||||
class TinyCBORParser
|
||||
{
|
||||
public:
|
||||
explicit TinyCBORParser(bytes const& _metadata): m_pos(0), m_metadata(_metadata)
|
||||
{
|
||||
assertThrow((m_pos + 1) < _metadata.size(), CBORException, "Input too short.");
|
||||
}
|
||||
unsigned mapItemCount()
|
||||
{
|
||||
assertThrow(nextType() == MajorType::Map, CBORException, "Fixed-length map expected.");
|
||||
return readLength();
|
||||
}
|
||||
string readKey()
|
||||
{
|
||||
return readString();
|
||||
}
|
||||
string readValue()
|
||||
{
|
||||
switch(nextType())
|
||||
{
|
||||
case MajorType::ByteString:
|
||||
return toHex(readBytes(readLength()));
|
||||
case MajorType::TextString:
|
||||
return readString();
|
||||
case MajorType::SimpleData:
|
||||
{
|
||||
unsigned value = nextImmediate();
|
||||
m_pos++;
|
||||
if (value == 20)
|
||||
return "false";
|
||||
else if (value == 21)
|
||||
return "true";
|
||||
else
|
||||
assertThrow(false, CBORException, "Unsupported simple value (not a boolean).");
|
||||
}
|
||||
default:
|
||||
assertThrow(false, CBORException, "Unsupported value type.");
|
||||
}
|
||||
}
|
||||
private:
|
||||
enum class MajorType
|
||||
{
|
||||
ByteString,
|
||||
TextString,
|
||||
Map,
|
||||
SimpleData
|
||||
};
|
||||
MajorType nextType() const
|
||||
{
|
||||
unsigned value = (m_metadata.at(m_pos) >> 5) & 0x7;
|
||||
switch (value)
|
||||
{
|
||||
case 2: return MajorType::ByteString;
|
||||
case 3: return MajorType::TextString;
|
||||
case 5: return MajorType::Map;
|
||||
case 7: return MajorType::SimpleData;
|
||||
default: assertThrow(false, CBORException, "Unsupported major type.");
|
||||
}
|
||||
}
|
||||
unsigned nextImmediate() const { return m_metadata.at(m_pos) & 0x1f; }
|
||||
unsigned readLength()
|
||||
{
|
||||
unsigned length = m_metadata.at(m_pos++) & 0x1f;
|
||||
if (length < 24)
|
||||
return length;
|
||||
if (length == 24)
|
||||
return m_metadata.at(m_pos++);
|
||||
// Unsupported length kind. (Only by this parser.)
|
||||
assertThrow(false, CBORException, string("Unsupported length ") + to_string(length));
|
||||
}
|
||||
bytes readBytes(unsigned length)
|
||||
{
|
||||
bytes ret{m_metadata.begin() + m_pos, m_metadata.begin() + m_pos + length};
|
||||
m_pos += length;
|
||||
return ret;
|
||||
}
|
||||
string readString()
|
||||
{
|
||||
// Expect a text string.
|
||||
assertThrow(nextType() == MajorType::TextString, CBORException, "String expected.");
|
||||
bytes tmp{readBytes(readLength())};
|
||||
return string{tmp.begin(), tmp.end()};
|
||||
}
|
||||
unsigned m_pos;
|
||||
bytes const& m_metadata;
|
||||
};
|
||||
|
||||
boost::optional<map<string, string>> parseCBORMetadata(bytes const& _metadata)
|
||||
{
|
||||
try
|
||||
{
|
||||
TinyCBORParser parser(_metadata);
|
||||
map<string, string> ret;
|
||||
unsigned count = parser.mapItemCount();
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
string key = parser.readKey();
|
||||
string value = parser.readValue();
|
||||
ret[move(key)] = move(value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
catch (CBORException const&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool isValidMetadata(string const& _metadata)
|
||||
{
|
||||
Json::Value metadata;
|
||||
|
@ -20,6 +20,10 @@
|
||||
*/
|
||||
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace dev
|
||||
@ -37,6 +41,15 @@ bytes bytecodeSansMetadata(bytes const& _bytecode);
|
||||
/// Throws exception on invalid hex string.
|
||||
std::string bytecodeSansMetadata(std::string const& _bytecode);
|
||||
|
||||
/// Parse CBOR metadata into a map. Expects the input CBOR to be a
|
||||
/// fixed length map, with each key being a string. The values
|
||||
/// are parsed as follows:
|
||||
/// - strings into strings
|
||||
/// - bytes into hex strings
|
||||
/// - booleans into "true"/"false" strings
|
||||
/// - everything else is invalid
|
||||
boost::optional<std::map<std::string, std::string>> parseCBORMetadata(bytes const& _metadata);
|
||||
|
||||
/// Expects a serialised metadata JSON and returns true if the
|
||||
/// content is valid metadata.
|
||||
bool isValidMetadata(std::string const& _metadata);
|
||||
|
Loading…
Reference in New Issue
Block a user