diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index c8388ad02..14827bf7f 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -4,6 +4,7 @@ #include #include +#include SField sfInvalid(-1), sfGeneric(0); @@ -19,13 +20,46 @@ static boost::mutex SField::mapMutex; SField::ref SField::getField(int code); { + int type = code >> 16; + int field = code % 0xffff; + if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256 return sfInvalid; + boost::mutex::scoped_lock sl(mapMutex); std::map it = unknownFieldMap.Find(code); if (it != codeToField.end()) return *(it->second); - return *(new SField(code, static_cast(code>>16), code&0xffff, NULL)); + switch(type) + { // types we are willing to dynamically extend + +#define FIELD(name, type, index) +#define TYPE(name, type, index) case sf##name: +#include "SerializeProto.h" +#undef FIELD +#undef TYPE + + break; + default: + return sfInvalid; + } + + return *(new SField(code, static_cast(type), field, NULL)); +} + +SField::ref SField::getField(int type, int value) +{ + return getField(FIELD_CODE(type, value)); +} + +std::string SField::getName() cosnt +{ + if (fieldName != NULL) + return fieldName; + if (fieldValue == 0) + return ""; + return boost::lexical_cast(static_cast(fieldType)) + "/" + + boost::lexical_cast(fieldValue); } diff --git a/src/FieldNames.h b/src/FieldNames.h index db29e0ebd..443232044 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -1,6 +1,8 @@ #ifndef __FIELDNAMES__ #define __FIELDNAMES__ +#include + #include #define FIELD_CODE(type, index) ((static_cast(type) << 16) | index) @@ -55,11 +57,18 @@ public: SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0), fieldName(NULL) { ; } static SField::ref getField(int fieldCode); + static SField::ref getField(int fieldType, int fieldValue); static SField::ref getField(SerializedTypeID type, int value) { return getField(FIELD_CODE(type, value)); } + std::string getName() const; + bool hasName() const { return (fieldName != NULL) || (fieldValue != 0); } + bool isGeneric() const { return fieldCode == 0; } bool isInvalid() const { return fieldCode == -1; } bool isKnown() const { return fieldType != STI_UNKNOWN; } + + bool operator==(const SField& f) const { return fieldCode == f.fieldCode; } + bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; } }; extern SField sfInvalid, sfGeneric; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index d935022cb..5ec0c8ad4 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -10,6 +10,8 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { + assert((id == STI_NOTPRESENT) || (id == name.fieldType)); + switch(id) { case STI_NOTPRESENT: @@ -48,6 +50,12 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, S case STI_PATHSET: return std::auto_ptr(new STPathSet(name)); + case STI_OBJECT: + return std::auto_ptr(new STObject(name)); + + case STI_ARRAY: + return std::auto_ptr(new STArray(name)); + default: throw std::runtime_error("Unknown object type"); } @@ -105,7 +113,7 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID } } -void STObject::set(const SOElement* elem) +void STObject::set(SOElement::ptr elem) { mData.empty(); mType.empty(); @@ -114,39 +122,70 @@ void STObject::set(const SOElement* elem) { mType.push_back(elem); if (elem->flags == SOE_OPTIONAL) - giveObject(makeDefaultObject(STI_NOTPRESENT, elem)); + giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_field)); else - giveObject(makeDefaultObject(elem->e_field, elem)); + giveObject(makeDefaultObject(elem->e_field.fieldType, elem->e_field)); ++elem; } } -STObject::STObject(const SOElement* elem, SField::ref name) : SerializedType(name) -{ - set(elem); -} - -void STObject::set(SField::ref name, SerializerIterator& sit, int depth = 0) +void STObject::setType(SOElement::ptrList t) { mData.empty(); - mType.empty(); - - fName = name; - - while(1) - { - int type, field. - sit.getFieldID(type, field); - if ((type == STI_ARRAY) && (field == 1)) - return; - SField::ref fn = SField::getField(type, field); - giveObject(makeDeserializedObject(static_cast type, fn, sit, depth + 1); - } + while (t->flags != SOE_END) + mType.push_back(t++); } -STObject::STObject(const SOElement* elem, SerializerIterator& sit, SField::refname) : SerializedType(name) +bool STObject::isValidForType() { - set(elem, sit); + BOOST_FOREACH(SOElement::ptr elem, mType) + { // are any required elemnents missing + if ((elem->flags == SOE_REQUIRED) && (getPField(elem->e_field) == NULL)) + { + Log(lsWARNING) << getName() << " missing required element " << elem->e_field.fieldName; + return false; + } + } + + BOOST_FOREACH(const SerializedType& elem, mData) + { // are any non-permitted elements present + if (!isFieldAllowed(elem.getFName())) + { + Log(lsWARNING) << getName() << " has non-permitted element " << elem.getName(); + return false; + } + } + + return true; +} + +bool STObject::isFieldAllowed(SField::ref field) +{ + BOOST_FOREACH(SOElement::ptr elem, mType) + { // are any required elemnents missing + if (elem->e_field == field) + return true; + } + return false; +} + +bool STObject::set(SOElement::ptrList elem, SerializerIterator& sit, int depth) +{ // return true = terminated with end-of-object + setType(elem); + + mData.empty(); + 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()) + throw std::runtime_error("Unknown field"); + giveObject(makeDeserializedObject(fn.fieldType, fn, sit, depth + 1)); + } + return false; } std::string STObject::getFullText() const diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 491e85a59..47e0d9639 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -11,34 +11,48 @@ // Serializable object/array types -struct SOElement +class SOElement { // An element in the description of a serialized object +public: + typedef SOElement const * ptr; // used to point to one element + typedef SOElement const * ptrList; // used to point to a terminated list of elements + SField::ref e_field; - SOE_Flags flags; + const SOE_Flags flags; }; class STObject : public SerializedType { protected: boost::ptr_vector mData; - std::vector mType; + std::vector mType; STObject* duplicate() const { return new STObject(*this); } static STObject* construct(SerializerIterator&, SField::ref); public: - STObject(SField *n = NULL) : SerializedType(n) { ; } - STObject(const SOElement *t, SField *n = NULL); - STObject(const SOElement *t, SerializerIterator& u, SField *n = NULL); + STObject() { ; } + + STObject(SField::ref name) : SerializedType(name) { ; } + + STObject(SOElement::ptrList type, SField::ref name) : SerializedType(name) + { set(type); } + + STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) + { set(type, sit); } + virtual ~STObject() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } - void set(const SOElement* t); - void set(const SOElement* t, SerializerIterator& u, int depth = 0); + void setType(SOElement const * t); + bool isValidForType(); + bool isFieldAllowed(SField::ref); + + void set(SOElement::ptrList); + bool set(SOElement::ptrList, SerializerIterator& u, int depth = 0); - int getLength() const; virtual SerializedTypeID getSType() const { return STI_OBJECT; } virtual bool isEquivalent(const SerializedType& t) const; @@ -111,8 +125,8 @@ public: SerializedType* makeFieldPresent(SField::ref field); void makeFieldAbsent(SField::ref field); - static std::auto_ptr makeDefaultObject(SerializedTypeID id, SField *name); - static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField *name, + static std::auto_ptr makeDefaultObject(SerializedTypeID id, SField::ref name); + static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField::ref name, SerializerIterator&, int depth); static void unitTest(); @@ -138,6 +152,7 @@ protected: public: STArray() { ; } + STArray(SField::ref f) : SerializedType(f) { ; } STArray(SField::ref f, const vector& v) : SerializedType(f), value(v) { ; } STArray(vector& v) : value(v) { ; } diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index d1278b864..ce997b5b8 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -37,7 +37,6 @@ public: SerializedTransaction(TransactionType type); // STObject functions - int getLength() const; SerializedTypeID getSType() const { return STI_TRANSACTION; } std::string getFullText() const; std::string getText() const; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 2085ab38a..d9bc627ab 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -49,7 +49,7 @@ public: { return std::auto_ptr(new SerializedType(name)); } void setFName(SField::ref n) { fName = &n; assert(fName); } - SField::ref getFName() { return *fName; } + SField::ref getFName() const { return *fName; } const char *getName() const { return fName->fieldName; } virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; }