diff --git a/src/Amount.cpp b/src/Amount.cpp index fbe6e0a5ac..ef8f417c7a 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "Config.h" @@ -54,6 +56,83 @@ std::string STAmount::getHumanCurrency() const return createHumanCurrency(mCurrency); } +STAmount::STAmount(SField::ref n, const Json::Value& v) + : SerializedType(n), mValue(0), mOffset(0), mIsNegative(false) +{ + Json::Value value, currency, issuer; + + if (v.isObject()) + { + value = v["value"]; + currency = v["currency"]; + issuer = v["issuer"]; + } + else if (v.isArray()) + { + value = v.get(Json::UInt(0), 0); + currency = v.get(Json::UInt(1), Json::nullValue); + issuer = v.get(Json::UInt(2), Json::nullValue); + } + else if (v.isString()) + { + std::string val = v.asString(); + std::vector elements; + boost::split(elements, val, boost::is_any_of("\t\n\r ,/")); + + if ((elements.size() < 0) || (elements.size() > 3)) + throw std::runtime_error("invalid amount string"); + + value = elements[0]; + if (elements.size() > 0) + currency = elements[1]; + if (elements.size() > 1) + issuer = elements[2]; + } + else + value = v; + + mIsNative = !currency.isString() || currency.asString().empty() || (currency.asString() == SYSTEM_CURRENCY_CODE); + + if (value.isInt()) + { + if (value.asInt() >= 0) + mValue = value.asInt(); + else + { + mValue = -value.asInt(); + mIsNegative = true; + } + } + else if (value.isUInt()) + mValue = v.asUInt(); + else if (value.isString()) + { // FIXME: If it has a '.' we have to process it specially! + if (mIsNative) + { + int64 val = lexical_cast_st(value.asString()); + if (val >= 0) + mValue = val; + else + { + mValue = -val; + mIsNegative = true; + } + } + else + setValue(value.asString()); + } + else + throw std::runtime_error("invalid amount type"); + + if (mIsNative) + return; + + // parse currency and issuer + // WRITEME + + canonicalize(); +} + std::string STAmount::createHumanCurrency(const uint160& uCurrency) { std::string sCurrency; @@ -100,6 +179,94 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency) return sCurrency; } +bool STAmount::setValue(const std::string& sAmount) +{ // Note: mIsNative must be set already! + uint64 uValue; + int iOffset; + size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : "."); + bool bInteger = uDecimal == std::string::npos; + + mIsNegative = false; + if (bInteger) + { + try + { + int64 a = sAmount.empty() ? 0 : lexical_cast_st(sAmount); + if (a >= 0) + uValue = static_cast(a); + else + { + uValue = static_cast(-a); + mIsNegative = true; + } + + } + catch (...) + { + Log(lsINFO) << "Bad integer amount: " << sAmount; + + return false; + } + iOffset = 0; + } + else + { + // Example size decimal size-decimal offset + // ^1 2 0 2 -1 + // 123^ 4 3 1 0 + // 1^23 4 1 3 -2 + iOffset = -int(sAmount.size() - uDecimal - 1); + + + // Issolate integer and fraction. + uint64 uInteger; + int64 iInteger = uDecimal ? lexical_cast_st(sAmount.substr(0, uDecimal)) : 0; + if (iInteger >= 0) + uInteger = static_cast(iInteger); + else + { + uInteger = static_cast(-iInteger); + mIsNegative = true; + } + + + uint64 uFraction = iOffset ? lexical_cast_st(sAmount.substr(uDecimal+1)) : 0; + + // Scale the integer portion to the same offset as the fraction. + uValue = uInteger; + for (int i = -iOffset; i--;) + uValue *= 10; + + // Add in the fraction. + uValue += uFraction; + } + + if (mIsNative) + { + if (bInteger) + iOffset = -SYSTEM_CURRENCY_PRECISION; + + while (iOffset > -SYSTEM_CURRENCY_PRECISION) { + uValue *= 10; + --iOffset; + } + + while (iOffset < -SYSTEM_CURRENCY_PRECISION) { + uValue /= 10; + ++iOffset; + } + + mValue = uValue; + } + else + { + mValue = uValue; + mOffset = iOffset; + canonicalize(); + } + return true; +} + // Not meant to be the ultimate parser. For use by RPC which is supposed to be sane and trusted. // Native has special handling: // - Integer values are in base units. @@ -143,72 +310,7 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr return false; } - uint64 uValue; - int iOffset; - size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : "."); - bool bInteger = uDecimal == std::string::npos; - - if (bInteger) - { - try - { - uValue = sAmount.empty() ? 0 : boost::lexical_cast(sAmount); - } - catch (...) - { - Log(lsINFO) << "Bad integer amount: " << sAmount; - - return false; - } - iOffset = 0; - } - else - { - // Example size decimal size-decimal offset - // ^1 2 0 2 -1 - // 123^ 4 3 1 0 - // 1^23 4 1 3 -2 - iOffset = -int(sAmount.size()-uDecimal-1); - - - // Issolate integer and fraction. - uint64 uInteger = uDecimal ? boost::lexical_cast(sAmount.substr(0, uDecimal)) : 0; - uint64 uFraction = iOffset ? boost::lexical_cast(sAmount.substr(uDecimal+1)) : 0; - - // Scale the integer portion to the same offset as the fraction. - uValue = uInteger; - for (int i=-iOffset; i--;) - uValue *= 10; - - // Add in the fraction. - uValue += uFraction; - } - - if (mIsNative) - { - if (bInteger) - iOffset = -SYSTEM_CURRENCY_PRECISION; - - while (iOffset > -SYSTEM_CURRENCY_PRECISION) { - uValue *= 10; - --iOffset; - } - - while (iOffset < -SYSTEM_CURRENCY_PRECISION) { - uValue /= 10; - ++iOffset; - } - - mValue = uValue; - } - else - { - mValue = uValue; - mOffset = iOffset; - canonicalize(); - } - - return true; + return setValue(sAmount); } // amount = value * [10 ^ offset] @@ -387,14 +489,14 @@ std::string STAmount::getRaw() const if (mValue == 0) return "0"; if (mIsNative) { - if (mIsNegative) return std::string("-") + boost::lexical_cast(mValue); - else return boost::lexical_cast(mValue); + if (mIsNegative) return std::string("-") + lexical_cast_i(mValue); + else return lexical_cast_i(mValue); } if (mIsNegative) return mCurrency.GetHex() + ": -" + - boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset); else return mCurrency.GetHex() + ": " + - boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset); } std::string STAmount::getText() const @@ -403,20 +505,20 @@ std::string STAmount::getText() const if (mIsNative) { if (mIsNegative) - return std::string("-") + boost::lexical_cast(mValue); - else return boost::lexical_cast(mValue); + return std::string("-") + lexical_cast_i(mValue); + else return lexical_cast_i(mValue); } if ((mOffset < -25) || (mOffset > -5)) { if (mIsNegative) - return std::string("-") + boost::lexical_cast(mValue) + - "e" + boost::lexical_cast(mOffset); + return std::string("-") + lexical_cast_i(mValue) + + "e" + lexical_cast_i(mOffset); else - return boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + return lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset); } std::string val = "000000000000000000000000000"; - val += boost::lexical_cast(mValue); + val += lexical_cast_i(mValue); val += "00000000000000000000000"; std::string pre = val.substr(0, mOffset + 43); diff --git a/src/FieldNames.h b/src/FieldNames.h index ed51006499..784900c148 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -28,7 +28,7 @@ enum SerializedTypeID enum SOE_Flags { - SOE_END = -1, // marks end of object + SOE_INVALID = -1, SOE_REQUIRED = 0, // required SOE_OPTIONAL = 1, // optional }; diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 9f0ed403ac..c696d72ed2 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -1,101 +1,118 @@ #include "LedgerFormats.h" -#define LEF_BASE \ - { sfLedgerIndex, SOE_OPTIONAL }, \ - { sfLedgerEntryType, SOE_REQUIRED }, \ - { sfFlags, SOE_REQUIRED }, +std::map LedgerEntryFormat::byType; +std::map LedgerEntryFormat::byName; -LedgerEntryFormat LedgerFormats[]= -{ - { "AccountRoot", ltACCOUNT_ROOT, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfSequence, SOE_REQUIRED }, - { sfBalance, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfAuthorizedKey, SOE_OPTIONAL }, - { sfEmailHash, SOE_OPTIONAL }, - { sfWalletLocator, SOE_OPTIONAL }, - { sfMessageKey, SOE_OPTIONAL }, - { sfTransferRate, SOE_OPTIONAL }, - { sfDomain, SOE_OPTIONAL }, - { sfPublishHash, SOE_OPTIONAL }, - { sfPublishSize, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "Contract", ltCONTRACT, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfBalance, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfIssuer, SOE_REQUIRED }, - { sfOwner, SOE_REQUIRED }, - { sfExpiration, SOE_REQUIRED }, - { sfBondAmount, SOE_REQUIRED }, - { sfCreateCode, SOE_REQUIRED }, - { sfFundCode, SOE_REQUIRED }, - { sfRemoveCode, SOE_REQUIRED }, - { sfExpireCode, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "DirectoryNode", ltDIR_NODE, { LEF_BASE - { sfIndexes, SOE_REQUIRED }, - { sfIndexNext, SOE_OPTIONAL }, - { sfIndexPrevious, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "GeneratorMap", ltGENERATOR_MAP, { LEF_BASE - { sfGenerator, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "Nickname", ltNICKNAME, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfMinimumOffer, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "Offer", ltOFFER, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfSequence, SOE_REQUIRED }, - { sfTakerPays, SOE_REQUIRED }, - { sfTakerGets, SOE_REQUIRED }, - { sfBookDirectory, SOE_REQUIRED }, - { sfBookNode, SOE_REQUIRED }, - { sfOwnerNode, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfExpiration, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "RippleState", ltRIPPLE_STATE, { LEF_BASE - { sfBalance, SOE_REQUIRED }, - { sfLowLimit, SOE_REQUIRED }, - { sfHighLimit, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfLowQualityIn, SOE_OPTIONAL }, - { sfLowQualityOut, SOE_OPTIONAL }, - { sfHighQualityIn, SOE_OPTIONAL }, - { sfHighQualityOut, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { NULL, ltINVALID } -}; +#define LEF_BASE \ + << SOElement(sfLedgerIndex, SOE_OPTIONAL) \ + << SOElement(sfLedgerEntryType, SOE_REQUIRED) \ + << SOElement(sfFlags, SOE_REQUIRED) -LedgerEntryFormat* getLgrFormat(LedgerEntryType t) +#define DECLARE_LEF(name, type) lef = new LedgerEntryFormat(#name, type); (*lef) LEF_BASE + +static bool LEFInit() { - return getLgrFormat(static_cast(t)); + LedgerEntryFormat* lef; + + DECLARE_LEF(AccountRoot, ltACCOUNT_ROOT) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfSequence, SOE_REQUIRED) + << SOElement(sfBalance, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfAuthorizedKey, SOE_OPTIONAL) + << SOElement(sfEmailHash, SOE_OPTIONAL) + << SOElement(sfWalletLocator, SOE_OPTIONAL) + << SOElement(sfMessageKey, SOE_OPTIONAL) + << SOElement(sfTransferRate, SOE_OPTIONAL) + << SOElement(sfDomain, SOE_OPTIONAL) + << SOElement(sfPublishHash, SOE_OPTIONAL) + << SOElement(sfPublishSize, SOE_OPTIONAL) + ; + + DECLARE_LEF(Contract, ltCONTRACT) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfBalance, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfIssuer, SOE_REQUIRED) + << SOElement(sfOwner, SOE_REQUIRED) + << SOElement(sfExpiration, SOE_REQUIRED) + << SOElement(sfBondAmount, SOE_REQUIRED) + << SOElement(sfCreateCode, SOE_REQUIRED) + << SOElement(sfFundCode, SOE_REQUIRED) + << SOElement(sfRemoveCode, SOE_REQUIRED) + << SOElement(sfExpireCode, SOE_REQUIRED) + ; + + DECLARE_LEF(DirectoryNode, ltDIR_NODE) + << SOElement(sfIndexes, SOE_REQUIRED) + << SOElement(sfIndexNext, SOE_OPTIONAL) + << SOElement(sfIndexPrevious, SOE_OPTIONAL) + ; + + DECLARE_LEF(GeneratorMap, ltGENERATOR_MAP) + << SOElement(sfGenerator, SOE_REQUIRED) + ; + + DECLARE_LEF(Nickname, ltNICKNAME) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfMinimumOffer, SOE_OPTIONAL) + ; + + DECLARE_LEF(Offer, ltOFFER) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfSequence, SOE_REQUIRED) + << SOElement(sfTakerPays, SOE_REQUIRED) + << SOElement(sfTakerGets, SOE_REQUIRED) + << SOElement(sfBookDirectory, SOE_REQUIRED) + << SOElement(sfBookNode, SOE_REQUIRED) + << SOElement(sfOwnerNode, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfExpiration, SOE_OPTIONAL) + ; + + DECLARE_LEF(RippleState, ltRIPPLE_STATE) + << SOElement(sfBalance, SOE_REQUIRED) + << SOElement(sfLowLimit, SOE_REQUIRED) + << SOElement(sfHighLimit, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfLowQualityIn, SOE_OPTIONAL) + << SOElement(sfLowQualityOut, SOE_OPTIONAL) + << SOElement(sfHighQualityIn, SOE_OPTIONAL) + << SOElement(sfHighQualityOut, SOE_OPTIONAL) + ; + + return true; } -LedgerEntryFormat* getLgrFormat(int t) +bool LEFInitComplete = LEFInit(); + +LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(LedgerEntryType t) { - LedgerEntryFormat* f = LedgerFormats; - while (f->t_name != NULL) - { - if (f->t_type == t) - return f; - ++f; - } - return NULL; + std::map::iterator it = byType.find(static_cast(t)); + if (it == byType.end()) + return NULL; + return it->second; } + +LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(int t) +{ + std::map::iterator it = byType.find((t)); + if (it == byType.end()) + return NULL; + return it->second; +} + +LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(const std::string& t) +{ + std::map::iterator it = byName.find((t)); + if (it == byName.end()) + return NULL; + return it->second; +} + // vim:ts=4 diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 7b4a95683e..947cb65be5 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -39,15 +39,31 @@ enum LedgerSpecificFlags lsfPassive = 0x00010000, }; -struct LedgerEntryFormat +class LedgerEntryFormat { - const char * t_name; - LedgerEntryType t_type; - SOElement elements[24]; +public: + std::string t_name; + LedgerEntryType t_type; + std::vector elements; + + static std::map byType; + static std::map byName; + + LedgerEntryFormat(const char *name, LedgerEntryType type) : t_name(name), t_type(type) + { + byName[name] = this; + byType[type] = this; + } + LedgerEntryFormat& operator<<(const SOElement& el) + { + elements.push_back(new SOElement(el)); + return *this; + } + + static LedgerEntryFormat* getLgrFormat(LedgerEntryType t); + static LedgerEntryFormat* getLgrFormat(const std::string& t); + static LedgerEntryFormat* getLgrFormat(int t); }; -extern LedgerEntryFormat LedgerFormats[]; -extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t); -extern LedgerEntryFormat* getLgrFormat(int t); #endif // vim:ts=4 diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 587e70cc0e..ad09a292dd 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1809,11 +1809,11 @@ Json::Value RPCServer::doSend(const Json::Value& params) if (params.size() >= 6) sDstIssuer = params[5u].asString(); - if (params.size() >= 7) - sSrcCurrency = params[6u].asString(); - if (params.size() >= 8) - sSrcIssuer = params[7u].asString(); + sSrcCurrency = params[7u].asString(); + + if (params.size() >= 9) + sSrcIssuer = params[8u].asString(); if (params.size() >= 9) sSrcIssuer = params[8u].asString(); diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 9a57267eb3..acc58da3c1 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -10,7 +10,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint { set(sit); uint16 type = getFieldU16(sfLedgerEntryType); - mFormat = getLgrFormat(static_cast(type)); + mFormat = LedgerEntryFormat::getLgrFormat(static_cast(type)); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; @@ -25,7 +25,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& set(sit); uint16 type = getFieldU16(sfLedgerEntryType); - mFormat = getLgrFormat(static_cast(type)); + mFormat = LedgerEntryFormat::getLgrFormat(static_cast(type)); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; @@ -39,7 +39,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sfLedgerEntry), mType(type) { - mFormat = getLgrFormat(type); + mFormat = LedgerEntryFormat::getLgrFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); set(mFormat->elements); setFieldU16(sfLedgerEntryType, static_cast(mFormat->t_type)); diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index a217c02681..74137bcc37 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -8,6 +8,8 @@ #include "../json/writer.h" #include "Log.h" +#include "LedgerFormats.h" +#include "TransactionFormats.h" std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { @@ -114,33 +116,32 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID } } -void STObject::set(SOElement::ptr elem) +void STObject::set(const std::vector& type) { mData.empty(); mType.empty(); - while (elem->flags != SOE_END) + BOOST_FOREACH(const SOElement::ptr& elem, type) { mType.push_back(elem); if (elem->flags == SOE_OPTIONAL) giveObject(makeNonPresentObject(elem->e_field)); else giveObject(makeDefaultObject(elem->e_field)); - ++elem; } } -bool STObject::setType(SOElement::ptrList t) +bool STObject::setType(const std::vector &type) { boost::ptr_vector newData; bool valid = true; mType.empty(); - while (t->flags != SOE_END) + BOOST_FOREACH(const SOElement::ptr& elem, type) { bool match = false; for (boost::ptr_vector::iterator it = mData.begin(); it != mData.end(); ++it) - if (it->getFName() == t->e_field) + if (it->getFName() == elem->e_field) { match = true; newData.push_back(mData.release(it).release()); @@ -149,15 +150,15 @@ bool STObject::setType(SOElement::ptrList t) if (!match) { - if (t->flags != SOE_OPTIONAL) + if (elem->flags != SOE_OPTIONAL) { Log(lsTRACE) << "setType !valid missing"; valid = false; } - newData.push_back(makeNonPresentObject(t->e_field)); + newData.push_back(makeNonPresentObject(elem->e_field)); } - mType.push_back(t++); + mType.push_back(elem); } if (mData.size() != 0) { @@ -740,7 +741,7 @@ Json::Value STObject::getJson(int options) const if (it.getSType() != STI_NOTPRESENT) { if (!it.getFName().hasName()) - ret[boost::lexical_cast(index)] = it.getJson(options); + ret[lexical_cast_i(index)] = it.getJson(options); else ret[it.getName()] = it.getJson(options); } @@ -813,31 +814,41 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field) return new STArray(field, value); } -std::auto_ptr STObject::parseJson(const Json::Value& object, SField::ref name, int depth) +std::auto_ptr 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& name = *it; - const Json::Value& value = object[name]; + const std::string& fieldName = *it; + const Json::Value& value = object[fieldName]; - SField::ref field = SField::getField(name); + SField::ref field = SField::getField(fieldName); if (field == sfInvalid) - throw std::runtime_error("Unknown field: " + name); + throw std::runtime_error("Unknown field: " + fieldName); switch (field.fieldType) { case STI_UINT8: if (value.isString()) - data.push_back(new STUInt8(field, boost::lexical_cast(value.asString()))); - else if (value.isInt()) - data.push_back(new STUInt8(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt8(field, lexical_cast_st(value.asString()))); + 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()) - data.push_back(new STUInt8(field, boost::lexical_cast(value.asUInt()))); + { + 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; @@ -846,75 +857,123 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r if (value.isString()) { std::string strValue = value.asString(); - if (!strValue.empty() && (strValue[0]<'0' || strValue[0]>'9')) + if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9'))) { if (field == sfTransactionType) { - // WRITEME + 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) { - // WRITEME + 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"); } - data.push_back(new STUInt16(field, boost::lexical_cast(strValue))); + else + data.push_back(new STUInt16(field, lexical_cast_st(strValue))); } else if (value.isInt()) - data.push_back(new STUInt16(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt16(field, range_check_cast(value.asInt(), 0, 65535))); else if (value.isUInt()) - data.push_back(new STUInt16(field, boost::lexical_cast(value.asUInt()))); + 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, boost::lexical_cast(value.asString()))); + data.push_back(new STUInt32(field, lexical_cast_st(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt32(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt32(field, range_check_cast(value.asInt(), 0, 4294967295))); else if (value.isUInt()) - data.push_back(new STUInt32(field, boost::lexical_cast(value.asUInt()))); + 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, boost::lexical_cast(value.asString()))); + data.push_back(new STUInt64(field, lexical_cast_st(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt64(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt64(field, + range_check_cast(value.asInt(), 0, 18446744073709551615ull))); else if (value.isUInt()) - data.push_back(new STUInt64(field, boost::lexical_cast(value.asUInt()))); + data.push_back(new STUInt64(field, static_cast(value.asUInt()))); else throw std::runtime_error("Incorrect type"); break; case STI_HASH128: - // WRITEME + if (value.isString()) + data.push_back(new STHash128(field, value.asString())); + else + throw std::runtime_error("Incorrect type"); + break; case STI_HASH160: - // WRITEME + if (value.isString()) + data.push_back(new STHash160(field, value.asString())); + else + throw std::runtime_error("Incorrect type"); + break; case STI_HASH256: - // WRITEME + if (value.isString()) + data.push_back(new STHash256(field, value.asString())); + else + throw std::runtime_error("Incorrect type"); + break; case STI_VL: - // WRITEME + if (!value.isString()) + data.push_back(new STVariableLength(field, strUnHex(value.asString()))); + break; case STI_AMOUNT: - // WRITEME + data.push_back(new STAmount(field, value)); + break; case STI_VECTOR256: // WRITEME case STI_PATHSET: // WRITEME + 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 + { // newcoin addres + NewcoinAddress a; + if (!a.setAccountPublic(strValue)) + throw std::runtime_error("Account invalid"); + data.push_back(new STAccount(field, a.getAccountID())); + } + } + break; case STI_OBJECT: - case STI_ACCOUNT: case STI_TRANSACTION: case STI_LEDGERENTRY: case STI_VALIDATION: @@ -932,7 +991,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r throw std::runtime_error("Invalid field type"); } } - return std::auto_ptr(new STObject(name, data)); + return std::auto_ptr(new STObject(*name, data)); } #if 0 diff --git a/src/SerializedObject.h b/src/SerializedObject.h index a60a3efba2..6de71dcbf5 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -15,10 +15,11 @@ 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; const SOE_Flags flags; + + SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; } }; class STObject : public SerializedType @@ -35,23 +36,23 @@ public: STObject(SField::ref name) : SerializedType(name) { ; } - STObject(SOElement::ptrList type, SField::ref name) : SerializedType(name) + STObject(const std::vector& type, SField::ref name) : SerializedType(name) { set(type); } - STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) + STObject(const std::vector& type, SerializerIterator& sit, SField::ref name) : SerializedType(name) { set(sit); setType(type); } - static std::auto_ptr parseJson(const Json::Value& value, SField::ref name, int depth = 0); + static std::auto_ptr parseJson(const Json::Value& value, SField::ref name = sfGeneric, int depth = 0); virtual ~STObject() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name); - bool setType(SOElement::ptrList); + bool setType(const std::vector& type); bool isValidForType(); bool isFieldAllowed(SField::ref); - void set(SOElement::ptrList); + void set(const std::vector&); bool set(SerializerIterator& u, int depth = 0); virtual SerializedTypeID getSType() const { return STI_OBJECT; } diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 3c3643ea3e..617125c02e 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -9,7 +9,7 @@ SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type) { - mFormat = getTxnFormat(type); + mFormat = TransactionFormat::getTxnFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); set(mFormat->elements); @@ -28,7 +28,7 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject set(sit); mType = static_cast(getFieldU16(sfTransactionType)); - mFormat = getTxnFormat(mType); + mFormat = TransactionFormat::getTxnFormat(mType); if (!mFormat) throw std::runtime_error("invalid transaction type"); if (!setType(mFormat->elements)) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 4cee5f5c9b..097395b5ca 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -54,13 +54,13 @@ std::string STUInt16::getText() const { if (getFName() == sfLedgerEntryType) { - LedgerEntryFormat *f = getLgrFormat(value); + LedgerEntryFormat *f = LedgerEntryFormat::getLgrFormat(value); if (f != NULL) return f->t_name; } if (getFName() == sfTransactionType) { - TransactionFormat *f = getTxnFormat(value); + TransactionFormat *f = TransactionFormat::getTxnFormat(value); if (f != NULL) return f->t_name; } @@ -231,9 +231,14 @@ bool STVector256::isEquivalent(const SerializedType& t) const // STAccount // +STAccount::STAccount(SField::ref n, const uint160& v) : STVariableLength(n) +{ + peekValue().insert(peekValue().end(), v.begin(), v.end()); +} + bool STAccount::isValueH160() const { - return peekValue().size() == (160/8); + return peekValue().size() == (160 / 8); } void STAccount::setValueH160(const uint160& v) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 246e4cde1f..7bafa039d5 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -220,8 +220,6 @@ protected: : SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } - STAmount(SField::ref name, const Json::Value& value); - uint64 toUInt64() const; static uint64 muldiv(uint64, uint64, uint64); @@ -245,6 +243,8 @@ public: SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } + STAmount(SField::ref, const Json::Value&); + static STAmount createFromInt64(SField::ref n, int64 v); static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -288,6 +288,7 @@ public: void setIssuer(const uint160& uIssuer) { mIssuer = uIssuer; } const uint160& getCurrency() const { return mCurrency; } + bool setValue(const std::string& sAmount); bool setFullValue(const std::string& sAmount, const std::string& sCurrency = "", const std::string& sIssuer = ""); void setValue(const STAmount &); @@ -377,6 +378,8 @@ public: STHash128(const uint128& v) : value(v) { ; } STHash128(SField::ref n, const uint128& v) : SerializedType(n), value(v) { ; } + STHash128(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); } + STHash128(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); } STHash128(SField::ref n) : SerializedType(n) { ; } STHash128() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -405,6 +408,8 @@ public: STHash160(const uint160& v) : value(v) { ; } STHash160(SField::ref n, const uint160& v) : SerializedType(n), value(v) { ; } + STHash160(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); } + STHash160(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); } STHash160(SField::ref n) : SerializedType(n) { ; } STHash160() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -433,6 +438,8 @@ public: STHash256(const uint256& v) : value(v) { ; } STHash256(SField::ref n, const uint256& v) : SerializedType(n), value(v) { ; } + STHash256(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); } + STHash256(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); } STHash256(SField::ref n) : SerializedType(n) { ; } STHash256() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -490,6 +497,7 @@ public: STAccount(const std::vector& v) : STVariableLength(v) { ; } STAccount(SField::ref n, const std::vector& v) : STVariableLength(n, v) { ; } + STAccount(SField::ref n, const uint160& v); STAccount(SField::ref n) : STVariableLength(n) { ; } STAccount() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index 0a937c8d18..84b40eb8ac 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -3,18 +3,23 @@ #include "HashPrefixes.h" -SOElement SerializedValidation::sValidationFormat[] = { - { sfFlags, SOE_REQUIRED }, - { sfLedgerHash, SOE_REQUIRED }, - { sfLedgerSequence, SOE_OPTIONAL }, - { sfCloseTime, SOE_OPTIONAL }, - { sfLoadFee, SOE_OPTIONAL }, - { sfBaseFee, SOE_OPTIONAL }, - { sfSigningTime, SOE_REQUIRED }, - { sfSigningPubKey, SOE_REQUIRED }, - { sfInvalid, SOE_END } +std::vector sValidationFormat; + +static bool SVFInit() +{ + sValidationFormat.push_back(new SOElement(sfFlags, SOE_REQUIRED)); + sValidationFormat.push_back(new SOElement(sfLedgerHash, SOE_REQUIRED)); + sValidationFormat.push_back(new SOElement(sfLedgerSequence, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfCloseTime, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfLoadFee, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfBaseFee, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfSigningTime, SOE_REQUIRED)); + sValidationFormat.push_back(new SOElement(sfSigningPubKey, SOE_REQUIRED)); + return true; }; +bool SVFinitComplete = SVFInit(); + const uint32 SerializedValidation::sFullFlag = 0x00010000; SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature) diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index 299c35a0ed..c76b233c54 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -17,7 +17,6 @@ public: typedef boost::shared_ptr pointer; typedef const boost::shared_ptr& ref; - static SOElement sValidationFormat[16]; static const uint32 sFullFlag; // These throw if the object is not valid diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index cebc37a49c..32c7caa714 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -1,119 +1,138 @@ #include "TransactionFormats.h" -#define TF_BASE \ - { sfTransactionType, SOE_REQUIRED }, \ - { sfFlags, SOE_REQUIRED }, \ - { sfSourceTag, SOE_OPTIONAL }, \ - { sfAccount, SOE_REQUIRED }, \ - { sfSequence, SOE_REQUIRED }, \ - { sfFee, SOE_REQUIRED }, \ - { sfSigningPubKey, SOE_REQUIRED }, \ - { sfTxnSignature, SOE_OPTIONAL }, +std::map TransactionFormat::byType; +std::map TransactionFormat::byName; -TransactionFormat InnerTxnFormats[]= +#define TF_BASE \ + << SOElement(sfTransactionType, SOE_REQUIRED) \ + << SOElement(sfFlags, SOE_REQUIRED) \ + << SOElement(sfSourceTag, SOE_OPTIONAL) \ + << SOElement(sfAccount, SOE_REQUIRED) \ + << SOElement(sfSequence, SOE_REQUIRED) \ + << SOElement(sfFee, SOE_REQUIRED) \ + << SOElement(sfSigningPubKey, SOE_REQUIRED) \ + << SOElement(sfTxnSignature, SOE_OPTIONAL) + +#define DECLARE_TF(name, type) tf = new TransactionFormat(#name, type); (*tf) TF_BASE + +static bool TFInit() { - { "AccountSet", ttACCOUNT_SET, { TF_BASE - { sfEmailHash, SOE_OPTIONAL }, - { sfWalletLocator, SOE_OPTIONAL }, - { sfMessageKey, SOE_OPTIONAL }, - { sfDomain, SOE_OPTIONAL }, - { sfTransferRate, SOE_OPTIONAL }, - { sfPublishHash, SOE_OPTIONAL }, - { sfPublishSize, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "Claim", ttCLAIM, { TF_BASE - { sfGenerator, SOE_REQUIRED }, - { sfPublicKey, SOE_REQUIRED }, - { sfSignature, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "CreditSet", ttCREDIT_SET, { TF_BASE - { sfLimitAmount, SOE_OPTIONAL }, - { sfQualityIn, SOE_OPTIONAL }, - { sfQualityOut, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, + TransactionFormat* tf; + + DECLARE_TF(AccountSet, ttACCOUNT_SET) + << SOElement(sfEmailHash, SOE_OPTIONAL) + << SOElement(sfWalletLocator, SOE_OPTIONAL) + << SOElement(sfMessageKey, SOE_OPTIONAL) + << SOElement(sfDomain, SOE_OPTIONAL) + << SOElement(sfTransferRate, SOE_OPTIONAL) + << SOElement(sfPublishHash, SOE_OPTIONAL) + << SOElement(sfPublishSize, SOE_OPTIONAL) + ; + + DECLARE_TF(Claim, ttCLAIM) + << SOElement(sfGenerator, SOE_REQUIRED) + << SOElement(sfPublicKey, SOE_REQUIRED) + << SOElement(sfSignature, SOE_REQUIRED) + ; + + DECLARE_TF(CreditSet, ttCREDIT_SET) + << SOElement(sfLimitAmount, SOE_OPTIONAL) + << SOElement(sfQualityIn, SOE_OPTIONAL) + << SOElement(sfQualityOut, SOE_OPTIONAL) + ; + + /* - { "Invoice", ttINVOICE, { TF_BASE - { sfTarget, SOE_REQUIRED }, - { sfAmount, SOE_REQUIRED }, - { sfDestination, SOE_OPTIONAL }, - { sfIdentifier, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, + DECLARE_TF(Invoice, ttINVOICE) + << SOElement(sfTarget, SOE_REQUIRED) + << SOElement(sfAmount, SOE_REQUIRED) + << SOElement(sfDestination, SOE_OPTIONAL) + << SOElement(sfIdentifier, SOE_OPTIONAL) + ; + ) */ - { "NicknameSet", ttNICKNAME_SET, { TF_BASE - { sfNickname, SOE_REQUIRED }, - { sfMinimumOffer, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "OfferCreate", ttOFFER_CREATE, { TF_BASE - { sfTakerPays, SOE_REQUIRED }, - { sfTakerGets, SOE_REQUIRED }, - { sfExpiration, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "OfferCancel", ttOFFER_CANCEL, { TF_BASE - { sfOfferSequence, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "PasswordFund", ttPASSWORD_FUND, { TF_BASE - { sfDestination, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "PasswordSet", ttPASSWORD_SET, { TF_BASE - { sfAuthorizedKey, SOE_REQUIRED }, - { sfGenerator, SOE_REQUIRED }, - { sfPublicKey, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "Payment", ttPAYMENT, { TF_BASE - { sfDestination, SOE_REQUIRED }, - { sfAmount, SOE_REQUIRED }, - { sfSendMax, SOE_OPTIONAL }, - { sfPaths, SOE_OPTIONAL }, - { sfInvoiceID, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "WalletAdd", ttWALLET_ADD, { TF_BASE - { sfAmount, SOE_REQUIRED }, - { sfAuthorizedKey, SOE_REQUIRED }, - { sfPublicKey, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "Contract", ttCONTRACT, { TF_BASE - { sfExpiration, SOE_REQUIRED }, - { sfBondAmount, SOE_REQUIRED }, - { sfStampEscrow, SOE_REQUIRED }, - { sfRippleEscrow, SOE_REQUIRED }, - { sfCreateCode, SOE_OPTIONAL }, - { sfFundCode, SOE_OPTIONAL }, - { sfRemoveCode, SOE_OPTIONAL }, - { sfExpireCode, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "RemoveContract", ttCONTRACT_REMOVE, { TF_BASE - { sfTarget, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { NULL, ttINVALID } -}; -TransactionFormat* getTxnFormat(TransactionType t) -{ - return getTxnFormat(static_cast(t)); + DECLARE_TF(NicknameSet, ttNICKNAME_SET) + << SOElement(sfNickname, SOE_REQUIRED) + << SOElement(sfMinimumOffer, SOE_OPTIONAL) + ; + + DECLARE_TF(OfferCreate, ttOFFER_CREATE) + << SOElement(sfTakerPays, SOE_REQUIRED) + << SOElement(sfTakerGets, SOE_REQUIRED) + << SOElement(sfExpiration, SOE_OPTIONAL) + ; + + DECLARE_TF(OfferCancel, ttOFFER_CANCEL) + << SOElement(sfOfferSequence, SOE_REQUIRED) + ; + + DECLARE_TF(PasswordFund, ttPASSWORD_FUND) + << SOElement(sfDestination, SOE_REQUIRED) + ; + + DECLARE_TF(PasswordSet, ttPASSWORD_SET) + << SOElement(sfAuthorizedKey, SOE_REQUIRED) + << SOElement(sfGenerator, SOE_REQUIRED) + << SOElement(sfPublicKey, SOE_REQUIRED) + ; + + DECLARE_TF(Payment, ttPAYMENT) + << SOElement(sfDestination, SOE_REQUIRED) + << SOElement(sfAmount, SOE_REQUIRED) + << SOElement(sfSendMax, SOE_OPTIONAL) + << SOElement(sfPaths, SOE_OPTIONAL) + << SOElement(sfInvoiceID, SOE_OPTIONAL) + ; + + DECLARE_TF(WalletAdd, ttWALLET_ADD) + << SOElement(sfAmount, SOE_REQUIRED) + << SOElement(sfAuthorizedKey, SOE_REQUIRED) + << SOElement(sfPublicKey, SOE_REQUIRED) + ; + + DECLARE_TF(Contract, ttCONTRACT) + << SOElement(sfExpiration, SOE_REQUIRED) + << SOElement(sfBondAmount, SOE_REQUIRED) + << SOElement(sfStampEscrow, SOE_REQUIRED) + << SOElement(sfRippleEscrow, SOE_REQUIRED) + << SOElement(sfCreateCode, SOE_OPTIONAL) + << SOElement(sfFundCode, SOE_OPTIONAL) + << SOElement(sfRemoveCode, SOE_OPTIONAL) + << SOElement(sfExpireCode, SOE_OPTIONAL) + ; + + DECLARE_TF(RemoveContract, ttCONTRACT_REMOVE) + << SOElement(sfTarget, SOE_REQUIRED) + ; + + return true; } -TransactionFormat* getTxnFormat(int t) +bool TFInitComplete = TFInit(); + +TransactionFormat* TransactionFormat::getTxnFormat(TransactionType t) { - TransactionFormat* f = InnerTxnFormats; - while (f->t_name != NULL) - { - if (f->t_type == t) - return f; - ++f; - } - return NULL; + std::map::iterator it = byType.find(static_cast(t)); + if (it == byType.end()) + return NULL; + return it->second; } + +TransactionFormat* TransactionFormat::getTxnFormat(int t) +{ + std::map::iterator it = byType.find((t)); + if (it == byType.end()) + return NULL; + return it->second; +} + +TransactionFormat* TransactionFormat::getTxnFormat(const std::string& t) +{ + std::map::iterator it = byName.find((t)); + if (it == byName.end()) + return NULL; + return it->second; +} + // vim:ts=4 diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index 57b155285f..857a43189c 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -21,11 +21,30 @@ enum TransactionType ttCREDIT_SET = 20, }; -struct TransactionFormat +class TransactionFormat { - const char * t_name; - TransactionType t_type; - SOElement elements[24]; +public: + std::string t_name; + TransactionType t_type; + std::vector elements; + + static std::map byType; + static std::map byName; + + TransactionFormat(const char *name, TransactionType type) : t_name(name), t_type(type) + { + byName[name] = this; + byType[type] = this; + } + TransactionFormat& operator<<(const SOElement& el) + { + elements.push_back(new SOElement(el)); + return *this; + } + + static TransactionFormat* getTxnFormat(TransactionType t); + static TransactionFormat* getTxnFormat(const std::string& t); + static TransactionFormat* getTxnFormat(int t); }; const int TransactionMinLen = 32; @@ -44,8 +63,5 @@ const uint32 tfPartialPayment = 0x00020000; const uint32 tfLimitQuality = 0x00040000; const uint32 tfNoRippleDirect = 0x00080000; -extern TransactionFormat InnerTxnFormats[]; -extern TransactionFormat* getTxnFormat(TransactionType t); -extern TransactionFormat* getTxnFormat(int t); #endif // vim:ts=4 diff --git a/src/utils.h b/src/utils.h index 91c5ff9b36..eab185b34a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -171,7 +171,7 @@ template T lexical_cast_s(const std::string& string) } } -template std::string lexical_cast_i(T t) +template std::string lexical_cast_i(const T& t) { // lexicaly cast the selected type to a string. Does not throw try { @@ -183,6 +183,44 @@ template std::string lexical_cast_i(T t) } } +template T lexical_cast_st(const std::string& string) +{ // lexically cast a string to the selected type. Does throw + return boost::lexical_cast(string); +} + +template std::string lexical_cast_it(const T& t) +{ // lexicaly cast the selected type to a string. Does not throw + return boost::lexical_cast(t); +} + +template T range_check(const T& value, const T& minimum, const T& maximum) +{ + if ((value < minimum) || (value > maximum)) + throw std::runtime_error("Value out of range"); + return value; +} + +template T range_check_min(const T& value, const T& minimum) +{ + if (value < minimum) + throw std::runtime_error("Value out of range"); + return value; +} + +template T range_check_max(const T& value, const T& maximum) +{ + if (value > maximum) + throw std::runtime_error("Value out of range"); + return value; +} + +template T range_check_cast(const U& value, const T& minimum, const T& maximum) +{ + if ((value < minimum) || (value > maximum)) + throw std::runtime_error("Value out of range"); + return static_cast(value); +} + #endif // vim:ts=4