mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 02:55:50 +00:00
1337 lines
36 KiB
C++
1337 lines
36 KiB
C++
|
|
SETUP_LOG (STObject)
|
|
|
|
DECLARE_INSTANCE(SerializedObject);
|
|
DECLARE_INSTANCE(SerializedArray);
|
|
|
|
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;
|
|
}
|
|
|
|
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 rand");
|
|
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 rand");
|
|
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)
|
|
{
|
|
TransactionFormat* f = TransactionFormat::getTxnFormat(strValue);
|
|
if (!f)
|
|
throw std::runtime_error("Unknown transaction type");
|
|
data.push_back(new STUInt16(field, static_cast<uint16>(f->t_type)));
|
|
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(), 0, 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
|