SETUP_LOG (STObject) DECLARE_INSTANCE(SerializedObject); DECLARE_INSTANCE(SerializedArray); UPTR_T STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { assert((id == STI_NOTPRESENT) || (id == name.fieldType)); switch(id) { case STI_NOTPRESENT: return UPTR_T(new SerializedType(name)); case STI_UINT8: return UPTR_T(new STUInt8(name)); case STI_UINT16: return UPTR_T(new STUInt16(name)); case STI_UINT32: return UPTR_T(new STUInt32(name)); case STI_UINT64: return UPTR_T(new STUInt64(name)); case STI_AMOUNT: return UPTR_T(new STAmount(name)); case STI_HASH128: return UPTR_T(new STHash128(name)); case STI_HASH160: return UPTR_T(new STHash160(name)); case STI_HASH256: return UPTR_T(new STHash256(name)); case STI_VECTOR256: return UPTR_T(new STVector256(name)); case STI_VL: return UPTR_T(new STVariableLength(name)); case STI_ACCOUNT: return UPTR_T(new STAccount(name)); case STI_PATHSET: return UPTR_T(new STPathSet(name)); case STI_OBJECT: return UPTR_T(new STObject(name)); case STI_ARRAY: return UPTR_T(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 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 newData(type.peek().size()); bool valid = true; mType = &type; BOOST_FOREACH(const SOElement* elem, type.peek()) { bool match = false; for (boost::ptr_vector::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::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 STObject::deserialize(SerializerIterator& sit, SField::ref name) { STObject *o; UPTR_T 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 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::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(field) != NULL) s.addFieldID(STI_ARRAY, 1); else if (dynamic_cast(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(&t); if (!v) return false; boost::ptr_vector::const_iterator it1 = mData.begin(), end1 = mData.end(); boost::ptr_vector::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(rf); if (!cf) throw std::runtime_error("Wrong field type"); return *cf; } bool STObject::setFlag(uint32 f) { STUInt32* t = dynamic_cast(getPField(sfFlags, true)); if (!t) return false; t->setValue(t->getValue() | f); return true; } bool STObject::clearFlag(uint32 f) { STUInt32* t = dynamic_cast(getPField(sfFlags)); if (!t) return false; t->setValue(t->getValue() & ~f); return true; } uint32 STObject::getFlags(void) const { const STUInt32* t = dynamic_cast(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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::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(&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::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 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(terCode); else data.push_back(new STUInt8(field, lexical_cast_st(value.asString()))); } data.push_back(new STUInt8(field, lexical_cast_st(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(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(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(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(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(strValue))); } else if (value.isInt()) data.push_back(new STUInt16(field, range_check_cast(value.asInt(), 0, 65535))); else if (value.isUInt()) data.push_back(new STUInt16(field, range_check_cast(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(value.asString()))); else if (value.isInt()) data.push_back(new STUInt32(field, range_check_cast(value.asInt(), 0, 4294967295u))); else if (value.isUInt()) data.push_back(new STUInt32(field, static_cast(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(value.asInt(), 0, 18446744073709551615ull))); else if (value.isUInt()) data.push_back(new STUInt64(field, static_cast(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(&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(&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(&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(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