diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 554acf4b55..620c87eba2 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -42,8 +42,8 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, c case STI_ACCOUNT: return std::auto_ptr(new STAccount(name)); - case STI_PATH: - return std::auto_ptr(new STPath(name)); + case STI_PATHSET: + return std::auto_ptr(new STPathSet(name)); default: throw std::runtime_error("Unknown object type"); @@ -88,8 +88,8 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID case STI_ACCOUNT: return STAccount::deserialize(sit, name); - case STI_PATH: - return STPath::deserialize(sit, name); + case STI_PATHSET: + return STPathSet::deserialize(sit, name); default: throw std::runtime_error("Unknown object type"); diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 3998ada5a9..d6cce1cacd 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -258,72 +258,62 @@ bool STTaggedList::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STPath* STPath::construct(SerializerIterator& s, const char *name) +STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) { + std::vector paths; std::vector path; do { switch(s.get8()) { case STPathElement::typeEnd: - return new STPath(name, path); + if(path.empty()) + { + if (!paths.empty()) + throw std::runtime_error("empty last path"); + } + else paths.push_back(path); + return new STPathSet(name, paths); + + case STPathElement::typeBoundary: + if (path.empty()) + throw std::runtime_error("empty path"); + paths.push_back(path); + path.clear(); case STPathElement::typeAccount: - { - STPathElement element; - element.mType = STPathElement::typeAccount; - element.mNode = s.get160(); - path.push_back(element); + path.push_back(STPathElement(STPathElement::typeAccount, s.get160())); break; - } case STPathElement::typeOffer: - { - STPathElement element; - element.mType = STPathElement::typeOffer; - element.mNode = s.get160(); - path.push_back(element); + path.push_back(STPathElement(STPathElement::typeOffer, s.get160())); break; - } default: throw std::runtime_error("Unknown path element"); } } while(1); } -int STPath::getLength() const +int STPathSet::getLength() const { - int ret = 1; // for end of path - for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) - { - switch (it->mType) - { - case STPathElement::typeAccount: - ret += 1 + 160 / 8; // type, account ID - break; - - case STPathElement::typeOffer: - ret += 1 + 160 / 8; // type, account ID, and currency - break; - - default: throw std::runtime_error("Unknown path element"); - } - } - return ret; + int ret = 0; + for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) + ret += it->getSerializeSize(); + return (ret != 0) ? ret : (ret + 1); } Json::Value STPath::getJson(int) const { Json::Value ret(Json::arrayValue); - for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) + for (std::vector::const_iterator it = mPath.begin(), end = mPath.end(); it != end; ++it) { - switch (it->mType) + switch (it->getNodeType()) { case STPathElement::typeAccount: { Json::Value elem(Json::objectValue); NewcoinAddress account; - account.setAccountID(it->mNode); + account.setAccountID(it->getNode()); elem["Account"] = account.humanAccountID(); ret.append(elem); break; @@ -332,7 +322,7 @@ Json::Value STPath::getJson(int) const case STPathElement::typeOffer: { Json::Value elem(Json::objectValue); - elem["Offer"] = it->mNode.GetHex(); + elem["Offer"] = it->getNode().GetHex(); ret.append(elem); break; } @@ -343,26 +333,34 @@ Json::Value STPath::getJson(int) const return ret; } +Json::Value STPathSet::getJson(int options) const +{ + Json::Value ret(Json::arrayValue); + for (std::vector::const_iterator it = value.begin(), end = value.end(); it!=end; ++it) + ret.append(it->getJson(options)); + return ret; +} + std::string STPath::getText() const { - std::string ret; + std::string ret("["); bool first = true; - for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) + for (std::vector::const_iterator it = mPath.begin(), end = mPath.end(); it != end; ++it) { if (!first) ret += ", "; - switch (it->mType) + switch (it->getNodeType()) { case STPathElement::typeAccount: { NewcoinAddress account; - account.setAccountID(it->mNode); + account.setAccountID(it->getNode()); ret += account.humanAccountID(); break; } case STPathElement::typeOffer: { ret += "Offer("; - ret += it->mNode.GetHex(); + ret += it->getNode().GetHex(); ret += ")"; break; } @@ -371,28 +369,40 @@ std::string STPath::getText() const } first = false; } - return ret; + return ret + "]"; } -void STPath::add(Serializer& s) const +std::string STPathSet::getText() const { - for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) + std::string ret("{"); + bool firstPath = true; + for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) { - switch (it->mType) + if (!firstPath) { - case STPathElement::typeAccount: - s.add8(STPathElement::typeAccount); - s.add160(it->mNode); - break; + ret += ", "; + firstPath = false; + } + ret += it->getText(); + } + return ret + "}"; +} - case STPathElement::typeOffer: - s.add8(STPathElement::typeOffer); - s.add160(it->mNode); - break; - - default: throw std::runtime_error("Unknown path element"); +void STPathSet::add(Serializer& s) const +{ + bool firstPath = true; + for (std::vector::const_iterator pit = value.begin(), pend = value.end(); pit != pend; ++pit) + { + if (!firstPath) + { + s.add8(STPathElement::typeBoundary); + firstPath = false; + } + for (std::vector::const_iterator eit = pit->begin(), eend = pit->end(); eit != eend; ++eit) + { + s.add8(eit->getNodeType()); + s.add160(eit->getNode()); } } - s.add8(STPathElement::typeEnd); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 01ad34d955..a05b4c9c45 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -17,7 +17,7 @@ enum SerializedTypeID // standard types STI_OBJECT=1, STI_UINT8=2, STI_UINT16=3, STI_UINT32=4, STI_UINT64=5, STI_HASH128=6, STI_HASH160=7, STI_HASH256=8, STI_VL=9, STI_TL=10, - STI_AMOUNT=11, STI_PATH=12, + STI_AMOUNT=11, STI_PATHSET=12, // high level types STI_ACCOUNT=100, STI_TRANSACTION=101, STI_LEDGERENTRY=102 @@ -436,28 +436,62 @@ public: class STPathElement { public: - static const int typeEnd = 0; - static const int typeAccount = 1; // Rippling through an account - static const int typeOffer = 2; // Claiming an offer + static const int typeEnd = 0x00; + static const int typeAccount = 0x01; // Rippling through an account + static const int typeOffer = 0x02; // Claiming an offer + static const int typeBoundary = 0xFF; // boundary between alternate paths +protected: int mType; uint160 mNode; + +public: + STPathElement(int type, const uint160& node) : mType(type), mNode(node) { ; } + int getNodeType() const { return mType; } + bool isAccount() const { return mType == typeAccount; } + bool isOffer() const { return mType == typeOffer; } + const uint160& getNode() const { return mNode; } + + void setType(int type) { mType = type; } + void setNode(const uint160& n) { mNode = n; } }; -class STPath : public SerializedType +class STPath { protected: - std::vector value; + std::vector mPath; - STPath* duplicate() const { return new STPath(name, value); } - static STPath* construct(SerializerIterator&, const char* name = NULL); +public: + STPath() { ; } + STPath(const std::vector& p) : mPath(p) { ; } + + int getElementCount() const { return mPath.size(); } + bool isEmpty() const { return mPath.empty(); } + const STPathElement& getElement(int offset) const { return mPath[offset]; } + const STPathElement& getElemet(int offset) { return mPath[offset]; } + void addElement(const STPathElement& e) { mPath.push_back(e); } + void clear() { mPath.clear(); } + int getSerializeSize() const { return 1 + mPath.size() * 21; } + std::string getText() const; + Json::Value getJson(int) const; + std::vector::const_iterator begin() const { return mPath.begin(); } + std::vector::const_iterator end() const { return mPath.end(); } +}; + +class STPathSet : public SerializedType +{ // A set of zero or more payment paths +protected: + std::vector value; + + STPathSet* duplicate() const { return new STPathSet(name, value); } + static STPathSet* construct(SerializerIterator&, const char* name = NULL); public: - STPath() { ; } - STPath(const char* n) : SerializedType(n) { ; } - STPath(const std::vector& v) : value(v) { ; } - STPath(const char* n, const std::vector& v) : SerializedType(n), value(v) { ; } + STPathSet() { ; } + STPathSet(const char* n) : SerializedType(n) { ; } + STPathSet(const std::vector& v) : value(v) { ; } + STPathSet(const char* n, const std::vector& v) : SerializedType(n), value(v) { ; } static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) { return std::auto_ptr(construct(sit, name)); } @@ -466,12 +500,16 @@ public: void add(Serializer& s) const; virtual Json::Value getJson(int) const; - SerializedTypeID getSType() const { return STI_PATH; } - int getPathLength() const { return value.size(); } - const STPathElement& getElement(int off) const { return value[off]; } - STPathElement& peekElement(int off) { return value[off]; } - bool emptyPath() const { return value.empty(); } - void addPathElement(const STPathElement& e) { value.push_back(e); } + SerializedTypeID getSType() const { return STI_PATHSET; } + int getPathCount() const { return value.size(); } + const STPath& getPath(int off) const { return value[off]; } + STPath& peekPath(int off) { return value[off]; } + bool isEmpty() const { return value.empty(); } + void clear() { value.clear(); } + void addPath(const STPath& e) { value.push_back(e); } + + std::vector::const_iterator begin() const { return value.begin(); } + std::vector::const_iterator end() const { return value.end(); } }; class STTaggedList : public SerializedType