Files
rippled/modules/ripple_data/protocol/ripple_SerializedObject.cpp
2013-06-24 18:26:57 -07:00

1631 lines
44 KiB
C++

//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (STObject)
UPTR_T<SerializedType> STObject::makeDefaultObject (SerializedTypeID id, SField::ref name)
{
assert ((id == STI_NOTPRESENT) || (id == name.fieldType));
switch (id)
{
case STI_NOTPRESENT:
return UPTR_T<SerializedType> (new SerializedType (name));
case STI_UINT8:
return UPTR_T<SerializedType> (new STUInt8 (name));
case STI_UINT16:
return UPTR_T<SerializedType> (new STUInt16 (name));
case STI_UINT32:
return UPTR_T<SerializedType> (new STUInt32 (name));
case STI_UINT64:
return UPTR_T<SerializedType> (new STUInt64 (name));
case STI_AMOUNT:
return UPTR_T<SerializedType> (new STAmount (name));
case STI_HASH128:
return UPTR_T<SerializedType> (new STHash128 (name));
case STI_HASH160:
return UPTR_T<SerializedType> (new STHash160 (name));
case STI_HASH256:
return UPTR_T<SerializedType> (new STHash256 (name));
case STI_VECTOR256:
return UPTR_T<SerializedType> (new STVector256 (name));
case STI_VL:
return UPTR_T<SerializedType> (new STVariableLength (name));
case STI_ACCOUNT:
return UPTR_T<SerializedType> (new STAccount (name));
case STI_PATHSET:
return UPTR_T<SerializedType> (new STPathSet (name));
case STI_OBJECT:
return UPTR_T<SerializedType> (new STObject (name));
case STI_ARRAY:
return UPTR_T<SerializedType> (new STArray (name));
default:
WriteLog (lsFATAL, STObject) << "Object type: " << lexical_cast_i (id);
assert (false);
throw std::runtime_error ("Unknown object type");
}
}
// VFALCO TODO Remove the 'depth' parameter
UPTR_T<SerializedType> STObject::makeDeserializedObject (SerializedTypeID id, SField::ref name,
SerializerIterator& sit, int depth)
{
switch (id)
{
case STI_NOTPRESENT:
return SerializedType::deserialize (name);
case STI_UINT8:
return STUInt8::deserialize (sit, name);
case STI_UINT16:
return STUInt16::deserialize (sit, name);
case STI_UINT32:
return STUInt32::deserialize (sit, name);
case STI_UINT64:
return STUInt64::deserialize (sit, name);
case STI_AMOUNT:
return STAmount::deserialize (sit, name);
case STI_HASH128:
return STHash128::deserialize (sit, name);
case STI_HASH160:
return STHash160::deserialize (sit, name);
case STI_HASH256:
return STHash256::deserialize (sit, name);
case STI_VECTOR256:
return STVector256::deserialize (sit, name);
case STI_VL:
return STVariableLength::deserialize (sit, name);
case STI_ACCOUNT:
return STAccount::deserialize (sit, name);
case STI_PATHSET:
return STPathSet::deserialize (sit, name);
case STI_ARRAY:
return STArray::deserialize (sit, name);
case STI_OBJECT:
return STObject::deserialize (sit, name);
default:
throw std::runtime_error ("Unknown object type");
}
}
void STObject::set (const SOTemplate& type)
{
mData.clear ();
mType = &type;
BOOST_FOREACH (const SOElement * elem, type.peek ())
{
if (elem->flags != SOE_REQUIRED)
giveObject (makeNonPresentObject (elem->e_field));
else
giveObject (makeDefaultObject (elem->e_field));
}
}
bool STObject::setType (const SOTemplate& type)
{
boost::ptr_vector<SerializedType> newData (type.peek ().size ());
bool valid = true;
mType = &type;
BOOST_FOREACH (const SOElement * elem, type.peek ())
{
bool match = false;
for (boost::ptr_vector<SerializedType>::iterator it = mData.begin (); it != mData.end (); ++it)
if (it->getFName () == elem->e_field)
{
// matching entry, move to new vector
match = true;
if ((elem->flags == SOE_DEFAULT) && it->isDefault ())
{
WriteLog (lsWARNING, STObject) << "setType( " << getFName ().getName () << ") invalid default "
<< elem->e_field.fieldName;
valid = false;
}
newData.push_back (mData.release (it).release ()); // CAUTION: This renders 'it' invalid
break;
}
if (!match)
{
// no match found
if (elem->flags == SOE_REQUIRED)
{
WriteLog (lsWARNING, STObject) << "setType( " << getFName ().getName () << ") invalid missing "
<< elem->e_field.fieldName;
valid = false;
}
newData.push_back (makeNonPresentObject (elem->e_field).release ());
}
}
BOOST_FOREACH (const SerializedType & t, mData)
{
// Anything left over must be discardable
if (!t.getFName ().isDiscardable ())
{
WriteLog (lsWARNING, STObject) << "setType( " << getFName ().getName () << ") invalid leftover "
<< t.getFName ().getName ();
valid = false;
}
}
mData.swap (newData);
return valid;
}
bool STObject::isValidForType ()
{
boost::ptr_vector<SerializedType>::iterator it = mData.begin ();
BOOST_FOREACH (const SOElement * elem, mType->peek ())
{
if (it == mData.end ())
return false;
if (elem->e_field != it->getFName ())
return false;
++it;
}
return true;
}
bool STObject::isFieldAllowed (SField::ref field)
{
if (mType == NULL)
return true;
return mType->getIndex (field) != -1;
}
// OLD
/*
bool STObject::set(SerializerIterator& sit, int depth)
{ // return true = terminated with end-of-object
mData.clear();
while (!sit.empty())
{
int type, field;
sit.getFieldID(type, field);
if ((type == STI_OBJECT) && (field == 1)) // end of object indicator
return true;
SField::ref fn = SField::getField(type, field);
if (fn.isInvalid())
{
WriteLog (lsWARNING, STObject) << "Unknown field: field_type=" << type << ", field_name=" << field;
throw std::runtime_error("Unknown field");
}
giveObject(makeDeserializedObject(fn.fieldType, fn, sit, depth + 1));
}
return false;
}
*/
// return true = terminated with end-of-object
bool STObject::set (SerializerIterator& sit, int depth)
{
bool reachedEndOfObject = false;
// Empty the destination buffer
//
mData.clear ();
// Consume data in the pipe until we run out or reach the end
//
while (!reachedEndOfObject && !sit.empty ())
{
int type;
int field;
// Get the metadata for the next field
//
sit.getFieldID (type, field);
reachedEndOfObject = (type == STI_OBJECT) && (field == 1);
if (!reachedEndOfObject)
{
// Figure out the field
//
SField::ref fn = SField::getField (type, field);
if (fn.isInvalid ())
{
WriteLog (lsWARNING, STObject) << "Unknown field: field_type=" << type << ", field_name=" << field;
throw std::runtime_error ("Unknown field");
}
// Unflatten the field
//
giveObject (makeDeserializedObject (fn.fieldType, fn, sit, depth + 1));
}
}
return reachedEndOfObject;
}
UPTR_T<SerializedType> STObject::deserialize (SerializerIterator& sit, SField::ref name)
{
STObject* o;
UPTR_T<SerializedType> object (o = new STObject (name));
o->set (sit, 1);
return object;
}
bool STObject::hasMatchingEntry (const SerializedType& t)
{
const SerializedType* o = peekAtPField (t.getFName ());
if (!o)
return false;
return t == *o;
}
std::string STObject::getFullText () const
{
std::string ret;
bool first = true;
if (fName->hasName ())
{
ret = fName->getName ();
ret += " = {";
}
else ret = "{";
BOOST_FOREACH (const SerializedType & it, mData)
if (it.getSType () != STI_NOTPRESENT)
{
if (!first) ret += ", ";
else first = false;
ret += it.getFullText ();
}
ret += "}";
return ret;
}
void STObject::add (Serializer& s, bool withSigningFields) const
{
std::map<int, const SerializedType*> fields;
BOOST_FOREACH (const SerializedType & it, mData)
{
// pick out the fields and sort them
if ((it.getSType () != STI_NOTPRESENT) && it.getFName ().shouldInclude (withSigningFields))
fields.insert (std::make_pair (it.getFName ().fieldCode, &it));
}
typedef std::map<int, const SerializedType*>::value_type field_iterator;
BOOST_FOREACH (field_iterator & it, fields)
{
// insert them in sorted order
const SerializedType* field = it.second;
field->addFieldID (s);
field->add (s);
if (dynamic_cast<const STArray*> (field) != NULL)
s.addFieldID (STI_ARRAY, 1);
else if (dynamic_cast<const STObject*> (field) != NULL)
s.addFieldID (STI_OBJECT, 1);
}
}
std::string STObject::getText () const
{
std::string ret = "{";
bool first = false;
BOOST_FOREACH (const SerializedType & it, mData)
{
if (!first)
{
ret += ", ";
first = false;
}
ret += it.getText ();
}
ret += "}";
return ret;
}
bool STObject::isEquivalent (const SerializedType& t) const
{
const STObject* v = dynamic_cast<const STObject*> (&t);
if (!v)
return false;
boost::ptr_vector<SerializedType>::const_iterator it1 = mData.begin (), end1 = mData.end ();
boost::ptr_vector<SerializedType>::const_iterator it2 = v->mData.begin (), end2 = v->mData.end ();
while ((it1 != end1) && (it2 != end2))
{
if ((it1->getSType () != it2->getSType ()) || !it1->isEquivalent (*it2))
return false;
++it1;
++it2;
}
return (it1 == end1) && (it2 == end2);
}
uint256 STObject::getHash (uint32 prefix) const
{
Serializer s;
s.add32 (prefix);
add (s, true);
return s.getSHA512Half ();
}
uint256 STObject::getSigningHash (uint32 prefix) const
{
Serializer s;
s.add32 (prefix);
add (s, false);
return s.getSHA512Half ();
}
int STObject::getFieldIndex (SField::ref field) const
{
if (mType != NULL)
return mType->getIndex (field);
int i = 0;
BOOST_FOREACH (const SerializedType & elem, mData)
{
if (elem.getFName () == field)
return i;
++i;
}
return -1;
}
const SerializedType& STObject::peekAtField (SField::ref field) const
{
int index = getFieldIndex (field);
if (index == -1)
throw std::runtime_error ("Field not found");
return peekAtIndex (index);
}
SerializedType& STObject::getField (SField::ref field)
{
int index = getFieldIndex (field);
if (index == -1)
throw std::runtime_error ("Field not found");
return getIndex (index);
}
SField::ref STObject::getFieldSType (int index) const
{
return mData[index].getFName ();
}
const SerializedType* STObject::peekAtPField (SField::ref field) const
{
int index = getFieldIndex (field);
if (index == -1)
return NULL;
return peekAtPIndex (index);
}
SerializedType* STObject::getPField (SField::ref field, bool createOkay)
{
int index = getFieldIndex (field);
if (index == -1)
{
if (createOkay && isFree ())
return getPIndex (giveObject (makeDefaultObject (field)));
return NULL;
}
return getPIndex (index);
}
bool STObject::isFieldPresent (SField::ref field) const
{
int index = getFieldIndex (field);
if (index == -1)
return false;
return peekAtIndex (index).getSType () != STI_NOTPRESENT;
}
STObject& STObject::peekFieldObject (SField::ref field)
{
SerializedType* rf = getPField (field, true);
if (!rf)
throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT)
rf = makeFieldPresent (field);
STObject* cf = dynamic_cast<STObject*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
return *cf;
}
bool STObject::setFlag (uint32 f)
{
STUInt32* t = dynamic_cast<STUInt32*> (getPField (sfFlags, true));
if (!t)
return false;
t->setValue (t->getValue () | f);
return true;
}
bool STObject::clearFlag (uint32 f)
{
STUInt32* t = dynamic_cast<STUInt32*> (getPField (sfFlags));
if (!t)
return false;
t->setValue (t->getValue () & ~f);
return true;
}
bool STObject::isFlag (uint32 f)
{
return (getFlags () & f) == f;
}
uint32 STObject::getFlags (void) const
{
const STUInt32* t = dynamic_cast<const STUInt32*> (peekAtPField (sfFlags));
if (!t)
return 0;
return t->getValue ();
}
SerializedType* STObject::makeFieldPresent (SField::ref field)
{
int index = getFieldIndex (field);
if (index == -1)
{
if (!isFree ())
throw std::runtime_error ("Field not found");
return getPIndex (giveObject (makeNonPresentObject (field)));
}
SerializedType* f = getPIndex (index);
if (f->getSType () != STI_NOTPRESENT)
return f;
mData.replace (index, makeDefaultObject (f->getFName ()).release ());
return getPIndex (index);
}
void STObject::makeFieldAbsent (SField::ref field)
{
int index = getFieldIndex (field);
if (index == -1)
throw std::runtime_error ("Field not found");
const SerializedType& f = peekAtIndex (index);
if (f.getSType () == STI_NOTPRESENT)
return;
mData.replace (index, makeNonPresentObject (f.getFName ()).release ());
}
bool STObject::delField (SField::ref field)
{
int index = getFieldIndex (field);
if (index == -1)
return false;
delField (index);
return true;
}
void STObject::delField (int index)
{
mData.erase (mData.begin () + index);
}
std::string STObject::getFieldString (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
return rf->getText ();
}
unsigned char STObject::getFieldU8 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return 0; // optional field not present
const STUInt8* cf = dynamic_cast<const STUInt8*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
uint16 STObject::getFieldU16 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return 0; // optional field not present
const STUInt16* cf = dynamic_cast<const STUInt16*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
uint32 STObject::getFieldU32 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return 0; // optional field not present
const STUInt32* cf = dynamic_cast<const STUInt32*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
uint64 STObject::getFieldU64 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return 0; // optional field not present
const STUInt64* cf = dynamic_cast<const STUInt64*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
uint128 STObject::getFieldH128 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return uint128 (); // optional field not present
const STHash128* cf = dynamic_cast<const STHash128*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
uint160 STObject::getFieldH160 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return uint160 (); // optional field not present
const STHash160* cf = dynamic_cast<const STHash160*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
uint256 STObject::getFieldH256 (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf)
throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return uint256 (); // optional field not present
const STHash256* cf = dynamic_cast<const STHash256*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
RippleAddress STObject::getFieldAccount (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf)
throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return RippleAddress (); // optional field not present
const STAccount* cf = dynamic_cast<const STAccount*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
return cf->getValueNCA ();
}
uint160 STObject::getFieldAccount160 (SField::ref field) const
{
uint160 a;
const SerializedType* rf = peekAtPField (field);
if (!rf)
throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id != STI_NOTPRESENT)
{
const STAccount* cf = dynamic_cast<const STAccount*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
cf->getValueH160 (a);
}
return a;
}
Blob STObject::getFieldVL (SField::ref field) const
{
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return Blob (); // optional field not present
const STVariableLength* cf = dynamic_cast<const STVariableLength*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return cf->getValue ();
}
const STAmount& STObject::getFieldAmount (SField::ref field) const
{
static STAmount empty;
const SerializedType* rf = peekAtPField (field);
if (!rf)
throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT)
return empty; // optional field not present
const STAmount* cf = dynamic_cast<const STAmount*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
return *cf;
}
const STPathSet& STObject::getFieldPathSet (SField::ref field) const
{
static STPathSet empty;
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return empty; // optional field not present
const STPathSet* cf = dynamic_cast<const STPathSet*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return *cf;
}
const STVector256& STObject::getFieldV256 (SField::ref field) const
{
static STVector256 empty;
const SerializedType* rf = peekAtPField (field);
if (!rf) throw std::runtime_error ("Field not found");
SerializedTypeID id = rf->getSType ();
if (id == STI_NOTPRESENT) return empty; // optional field not present
const STVector256* cf = dynamic_cast<const STVector256*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
return *cf;
}
void STObject::setFieldU8 (SField::ref field, unsigned char v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STUInt8* cf = dynamic_cast<STUInt8*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldU16 (SField::ref field, uint16 v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STUInt16* cf = dynamic_cast<STUInt16*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldU32 (SField::ref field, uint32 v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STUInt32* cf = dynamic_cast<STUInt32*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldU64 (SField::ref field, uint64 v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STUInt64* cf = dynamic_cast<STUInt64*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldH128 (SField::ref field, const uint128& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STHash128* cf = dynamic_cast<STHash128*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldH160 (SField::ref field, const uint160& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STHash160* cf = dynamic_cast<STHash160*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldH256 (SField::ref field, uint256 const& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STHash256* cf = dynamic_cast<STHash256*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldV256 (SField::ref field, const STVector256& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STVector256* cf = dynamic_cast<STVector256*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldAccount (SField::ref field, const uint160& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STAccount* cf = dynamic_cast<STAccount*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValueH160 (v);
}
void STObject::setFieldVL (SField::ref field, Blob const& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STVariableLength* cf = dynamic_cast<STVariableLength*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
cf->setValue (v);
}
void STObject::setFieldAmount (SField::ref field, const STAmount& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STAmount* cf = dynamic_cast<STAmount*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
(*cf) = v;
}
void STObject::setFieldPathSet (SField::ref field, const STPathSet& v)
{
SerializedType* rf = getPField (field, true);
if (!rf) throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT) rf = makeFieldPresent (field);
STPathSet* cf = dynamic_cast<STPathSet*> (rf);
if (!cf) throw std::runtime_error ("Wrong field type");
(*cf) = v;
}
Json::Value STObject::getJson (int options) const
{
Json::Value ret (Json::objectValue);
int index = 1;
BOOST_FOREACH (const SerializedType & it, mData)
{
if (it.getSType () != STI_NOTPRESENT)
{
if (!it.getFName ().hasName ())
ret[lexical_cast_i (index)] = it.getJson (options);
else
ret[it.getName ()] = it.getJson (options);
}
}
return ret;
}
bool STObject::operator== (const STObject& obj) const
{
// This is not particularly efficient, and only compares data elements with binary representations
int matches = 0;
BOOST_FOREACH (const SerializedType & t, mData)
if ((t.getSType () != STI_NOTPRESENT) && t.getFName ().isBinary ())
{
// each present field must have a matching field
bool match = false;
BOOST_FOREACH (const SerializedType & t2, obj.mData)
if (t.getFName () == t2.getFName ())
{
if (t2 != t)
return false;
match = true;
++matches;
break;
}
if (!match)
{
Log (lsTRACE) << "STObject::operator==: no match for " << t.getFName ().getName ();
return false;
}
}
int fields = 0;
BOOST_FOREACH (const SerializedType & t2, obj.mData)
if ((t2.getSType () != STI_NOTPRESENT) && t2.getFName ().isBinary ())
++fields;
if (fields != matches)
{
Log (lsTRACE) << "STObject::operator==: " << fields << " fields, " << matches << " matches";
return false;
}
return true;
}
Json::Value STVector256::getJson (int options) const
{
Json::Value ret (Json::arrayValue);
BOOST_FOREACH (std::vector<uint256>::const_iterator::value_type vEntry, mValue)
ret.append (vEntry.ToString ());
return ret;
}
std::string STArray::getFullText () const
{
std::string r = "[";
bool first = true;
BOOST_FOREACH (const STObject & o, value)
{
if (!first)
r += ",";
r += o.getFullText ();
first = false;
}
r += "]";
return r;
}
std::string STArray::getText () const
{
std::string r = "[";
bool first = true;
BOOST_FOREACH (const STObject & o, value)
{
if (!first)
r += ",";
r += o.getText ();
first = false;
}
r += "]";
return r;
}
Json::Value STArray::getJson (int p) const
{
Json::Value v = Json::arrayValue;
int index = 1;
BOOST_FOREACH (const STObject & object, value)
{
if (object.getSType () != STI_NOTPRESENT)
{
Json::Value inner = Json::objectValue;
if (!object.getFName ().hasName ())
inner[lexical_cast_i (index)] = object.getJson (p);
else
inner[object.getName ()] = object.getJson (p);
v.append (inner);
index++;
}
}
return v;
}
void STArray::add (Serializer& s) const
{
BOOST_FOREACH (const STObject & object, value)
{
object.addFieldID (s);
object.add (s);
s.addFieldID (STI_OBJECT, 1);
}
}
bool STArray::isEquivalent (const SerializedType& t) const
{
const STArray* v = dynamic_cast<const STArray*> (&t);
if (!v)
return false;
return value == v->value;
}
STArray* STArray::construct (SerializerIterator& sit, SField::ref field)
{
vector value;
while (!sit.empty ())
{
int type, field;
sit.getFieldID (type, field);
if ((type == STI_ARRAY) && (field == 1))
break;
SField::ref fn = SField::getField (type, field);
if (fn.isInvalid ())
{
WriteLog (lsTRACE, STObject) << "Unknown field: " << type << "/" << field;
throw std::runtime_error ("Unknown field");
}
value.push_back (new STObject (fn));
value.rbegin ()->set (sit, 1);
}
return new STArray (field, value);
}
void STArray::sort (bool (*compare) (const STObject&, const STObject&))
{
value.sort (compare);
}
UPTR_T<STObject> STObject::parseJson (const Json::Value& object, SField::ref inName, int depth)
{
if (!object.isObject ())
throw std::runtime_error ("Value is not an object");
SField::ptr name = &inName;
boost::ptr_vector<SerializedType> data;
Json::Value::Members members (object.getMemberNames ());
for (Json::Value::Members::iterator it = members.begin (), end = members.end (); it != end; ++it)
{
const std::string& fieldName = *it;
const Json::Value& value = object[fieldName];
SField::ref field = SField::getField (fieldName);
if (field == sfInvalid)
throw std::runtime_error ("Unknown field: " + fieldName);
switch (field.fieldType)
{
case STI_UINT8:
if (value.isString ())
{
#if 0
if (field == sfTransactionResult)
{
TER terCode;
if (FUNCTION_THAT_DOESNT_EXIST (value.asString (), terCode))
value = static_cast<int> (terCode);
else
data.push_back (new STUInt8 (field, lexical_cast_st<unsigned char> (value.asString ())));
}
data.push_back (new STUInt8 (field, lexical_cast_st<unsigned char> (value.asString ())));
#endif
}
else if (value.isInt ())
{
if (value.asInt () < 0 || value.asInt () > 255)
throw std::runtime_error ("value out of range");
data.push_back (new STUInt8 (field, range_check_cast<unsigned char> (value.asInt (), 0, 255)));
}
else if (value.isUInt ())
{
if (value.asUInt () > 255)
throw std::runtime_error ("value out of range");
data.push_back (new STUInt8 (field, range_check_cast<unsigned char> (value.asUInt (), 0, 255)));
}
else
throw std::runtime_error ("Incorrect type");
break;
case STI_UINT16:
if (value.isString ())
{
std::string strValue = value.asString ();
if (!strValue.empty () && ((strValue[0] < '0') || (strValue[0] > '9')))
{
if (field == sfTransactionType)
{
TxFormat* f = TxFormats::getInstance ().findByName (strValue);
if (!f)
throw std::runtime_error ("Unknown transaction type");
data.push_back (new STUInt16 (field, static_cast<uint16> (f->getType ())));
if (*name == sfGeneric)
name = &sfTransaction;
}
else if (field == sfLedgerEntryType)
{
LedgerEntryFormat* f = LedgerEntryFormat::getLgrFormat (strValue);
if (!f)
throw std::runtime_error ("Unknown ledger entry type");
data.push_back (new STUInt16 (field, static_cast<uint16> (f->t_type)));
if (*name == sfGeneric)
name = &sfLedgerEntry;
}
else
throw std::runtime_error ("Invalid field data");
}
else
data.push_back (new STUInt16 (field, lexical_cast_st<uint16> (strValue)));
}
else if (value.isInt ())
data.push_back (new STUInt16 (field, range_check_cast<uint16> (value.asInt (), 0, 65535)));
else if (value.isUInt ())
data.push_back (new STUInt16 (field, range_check_cast<uint16> (value.asUInt (), 0, 65535)));
else
throw std::runtime_error ("Incorrect type");
break;
case STI_UINT32:
if (value.isString ())
{
data.push_back (new STUInt32 (field, lexical_cast_st<uint32> (value.asString ())));
}
else if (value.isInt ())
{
data.push_back (new STUInt32 (field, range_check_cast <uint32> (value.asInt (), 0u, 4294967295u)));
}
else if (value.isUInt ())
{
data.push_back (new STUInt32 (field, static_cast<uint32> (value.asUInt ())));
}
else
{
throw std::runtime_error ("Incorrect type");
}
break;
case STI_UINT64:
if (value.isString ())
data.push_back (new STUInt64 (field, uintFromHex (value.asString ())));
else if (value.isInt ())
data.push_back (new STUInt64 (field,
range_check_cast<uint64> (value.asInt (), 0, 18446744073709551615ull)));
else if (value.isUInt ())
data.push_back (new STUInt64 (field, static_cast<uint64> (value.asUInt ())));
else
throw std::runtime_error ("Incorrect type");
break;
case STI_HASH128:
if (value.isString ())
data.push_back (new STHash128 (field, value.asString ()));
else
throw std::runtime_error ("Incorrect type");
break;
case STI_HASH160:
if (value.isString ())
data.push_back (new STHash160 (field, value.asString ()));
else
throw std::runtime_error ("Incorrect type");
break;
case STI_HASH256:
if (value.isString ())
data.push_back (new STHash256 (field, value.asString ()));
else
throw std::runtime_error ("Incorrect type");
break;
case STI_VL:
if (!value.isString ())
throw std::runtime_error ("Incorrect type");
data.push_back (new STVariableLength (field, strUnHex (value.asString ())));
break;
case STI_AMOUNT:
data.push_back (new STAmount (field, value));
break;
case STI_VECTOR256:
if (!value.isArray ())
throw std::runtime_error ("Incorrect type");
{
data.push_back (new STVector256 (field));
STVector256* tail = dynamic_cast<STVector256*> (&data.back ());
assert (tail);
for (Json::UInt i = 0; !object.isValidIndex (i); ++i)
{
uint256 s;
s.SetHex (object[i].asString ());
tail->addValue (s);
}
}
break;
case STI_PATHSET:
if (!value.isArray ())
throw std::runtime_error ("Path set must be array");
{
data.push_back (new STPathSet (field));
STPathSet* tail = dynamic_cast<STPathSet*> (&data.back ());
assert (tail);
for (Json::UInt i = 0; value.isValidIndex (i); ++i)
{
STPath p;
if (!value[i].isArray ())
throw std::runtime_error ("Path must be array");
for (Json::UInt j = 0; value[i].isValidIndex (j); ++j)
{
// each element in this path has some combination of account, currency, or issuer
Json::Value pathEl = value[i][j];
if (!pathEl.isObject ())
throw std::runtime_error ("Path elements must be objects");
const Json::Value& account = pathEl["account"];
const Json::Value& currency = pathEl["currency"];
const Json::Value& issuer = pathEl["issuer"];
bool hasCurrency = false;
uint160 uAccount, uCurrency, uIssuer;
if (!account.isNull ())
{
// human account id
if (!account.isString ())
throw std::runtime_error ("path element accounts must be strings");
std::string strValue = account.asString ();
if (value.size () == 40) // 160-bit hex account value
uAccount.SetHex (strValue);
{
RippleAddress a;
if (!a.setAccountID (strValue))
throw std::runtime_error ("Account in path element invalid");
uAccount = a.getAccountID ();
}
}
if (!currency.isNull ())
{
// human currency
if (!currency.isString ())
throw std::runtime_error ("path element currencies must be strings");
hasCurrency = true;
if (currency.asString ().size () == 40)
uCurrency.SetHex (currency.asString ());
else if (!STAmount::currencyFromString (uCurrency, currency.asString ()))
throw std::runtime_error ("invalid currency");
}
if (!issuer.isNull ())
{
// human account id
if (!issuer.isString ())
throw std::runtime_error ("path element issuers must be strings");
if (issuer.asString ().size () == 40)
uIssuer.SetHex (issuer.asString ());
else
{
RippleAddress a;
if (!a.setAccountID (issuer.asString ()))
throw std::runtime_error ("path element issuer invalid");
uIssuer = a.getAccountID ();
}
}
p.addElement (STPathElement (uAccount, uCurrency, uIssuer, hasCurrency));
}
tail->addPath (p);
}
}
break;
case STI_ACCOUNT:
{
if (!value.isString ())
throw std::runtime_error ("Incorrect type");
std::string strValue = value.asString ();
if (value.size () == 40) // 160-bit hex account value
{
uint160 v;
v.SetHex (strValue);
data.push_back (new STAccount (field, v));
}
else
{
// ripple address
RippleAddress a;
if (!a.setAccountID (strValue))
{
WriteLog (lsINFO, STObject) << "Invalid acccount JSON: " << fieldName << ": " << strValue;
throw std::runtime_error ("Account invalid");
}
data.push_back (new STAccount (field, a.getAccountID ()));
}
}
break;
case STI_OBJECT:
case STI_TRANSACTION:
case STI_LEDGERENTRY:
case STI_VALIDATION:
if (!value.isObject ())
throw std::runtime_error ("Inner value is not an object");
if (depth > 64)
throw std::runtime_error ("Json nest depth exceeded");
data.push_back (parseJson (value, field, depth + 1).release ());
break;
case STI_ARRAY:
if (!value.isArray ())
throw std::runtime_error ("Inner value is not an array");
{
data.push_back (new STArray (field));
STArray* tail = dynamic_cast<STArray*> (&data.back ());
assert (tail);
for (Json::UInt i = 0; !object.isValidIndex (i); ++i)
tail->push_back (*STObject::parseJson (object[i], sfGeneric, depth + 1));
}
default:
throw std::runtime_error ("Invalid field type");
}
}
return UPTR_T<STObject> (new STObject (*name, data));
}
BOOST_AUTO_TEST_SUITE (SerializedObject)
BOOST_AUTO_TEST_CASE ( FieldManipulation_test )
{
if (sfGeneric.isUseful ())
BOOST_FAIL ("sfGeneric must not be useful");
SField sfTestVL (STI_VL, 255, "TestVL");
SField sfTestH256 (STI_HASH256, 255, "TestH256");
SField sfTestU32 (STI_UINT32, 255, "TestU32");
SField sfTestObject (STI_OBJECT, 255, "TestObject");
SOTemplate elements;
elements.push_back (SOElement (sfFlags, SOE_REQUIRED));
elements.push_back (SOElement (sfTestVL, SOE_REQUIRED));
elements.push_back (SOElement (sfTestH256, SOE_OPTIONAL));
elements.push_back (SOElement (sfTestU32, SOE_REQUIRED));
STObject object1 (elements, sfTestObject);
STObject object2 (object1);
if (object1.getSerializer () != object2.getSerializer ()) BOOST_FAIL ("STObject error 1");
if (object1.isFieldPresent (sfTestH256) || !object1.isFieldPresent (sfTestVL))
BOOST_FAIL ("STObject error");
object1.makeFieldPresent (sfTestH256);
if (!object1.isFieldPresent (sfTestH256)) BOOST_FAIL ("STObject Error 2");
if (object1.getFieldH256 (sfTestH256) != uint256 ()) BOOST_FAIL ("STObject error 3");
if (object1.getSerializer () == object2.getSerializer ())
{
WriteLog (lsINFO, STObject) << "O1: " << object1.getJson (0);
WriteLog (lsINFO, STObject) << "O2: " << object2.getJson (0);
BOOST_FAIL ("STObject error 4");
}
object1.makeFieldAbsent (sfTestH256);
if (object1.isFieldPresent (sfTestH256)) BOOST_FAIL ("STObject error 5");
if (object1.getFlags () != 0) BOOST_FAIL ("STObject error 6");
if (object1.getSerializer () != object2.getSerializer ()) BOOST_FAIL ("STObject error 7");
STObject copy (object1);
if (object1.isFieldPresent (sfTestH256)) BOOST_FAIL ("STObject error 8");
if (copy.isFieldPresent (sfTestH256)) BOOST_FAIL ("STObject error 9");
if (object1.getSerializer () != copy.getSerializer ()) BOOST_FAIL ("STObject error 10");
copy.setFieldU32 (sfTestU32, 1);
if (object1.getSerializer () == copy.getSerializer ()) BOOST_FAIL ("STObject error 11");
for (int i = 0; i < 1000; i++)
{
Blob j (i, 2);
object1.setFieldVL (sfTestVL, j);
Serializer s;
object1.add (s);
SerializerIterator it (s);
STObject object3 (elements, it, sfTestObject);
if (object1.getFieldVL (sfTestVL) != j) BOOST_FAIL ("STObject error");
if (object3.getFieldVL (sfTestVL) != j) BOOST_FAIL ("STObject error");
}
}
BOOST_AUTO_TEST_SUITE_END ();
// vim:ts=4