diff --git a/src/name-component.cpp b/src/name-component.cpp new file mode 100644 index 0000000..6b42900 --- /dev/null +++ b/src/name-component.cpp @@ -0,0 +1,199 @@ +#include "name.hpp" + +namespace ndn { +namespace name { + +bool +Component::equals(const Component& other) const +{ + if (value_size() != other.value_size()) + return false; + if (value_size() == 0 /* == other.value_size()*/) + return true; + + // somehow, behavior is wrong on OSX 10.9 when component is empty + // (probably some bug in STL...) + return std::equal(value_begin(), value_end(), other.value_begin()); +} + +std::ostream& +operator<<(std::ostream& os, const Component& component) +{ + component.toUri(os); + return os; +} + +Component::Component() + : Block(Tlv::NameComponent) +{ +} + +Component::Component(const Block& wire) + : Block(wire) +{ + if (type() != Tlv::NameComponent) + throw Error("Constructing name component from non name component TLV wire block"); +} + +Component::Component(const ConstBufferPtr& buffer) + : Block(Tlv::NameComponent, buffer) +{ +} + +Component::Component(const Buffer& value) + : Block(dataBlock(Tlv::NameComponent, value.buf(), value.size())) +{ +} + +Component::Component(const uint8_t* value, size_t valueLen) + : Block(dataBlock(Tlv::NameComponent, value, valueLen)) +{ +} + +Component::Component(const char* str) + : Block(dataBlock(Tlv::NameComponent, str, ::strlen(str))) +{ +} + +Component::Component(const std::string& str) + : Block(dataBlock(Tlv::NameComponent, str.c_str(), str.size())) +{ +} + +Component +Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset) +{ + std::string trimmedString(escapedString + beginOffset, escapedString + endOffset); + trim(trimmedString); + std::string value = unescape(trimmedString); + + if (value.find_first_not_of(".") == std::string::npos) { + // Special case for component of only periods. + if (value.size() <= 2) + // Zero, one or two periods is illegal. Ignore this component. + return Component(); + else + // Remove 3 periods. + return Component(reinterpret_cast(&value[3]), value.size() - 3); + } + else + return Component(reinterpret_cast(&value[0]), value.size()); +} + + +void +Component::toUri(std::ostream& result) const +{ + const uint8_t* valuePtr = value(); + size_t valueSize = value_size(); + + bool gotNonDot = false; + for (unsigned i = 0; i < valueSize; ++i) { + if (valuePtr[i] != 0x2e) { + gotNonDot = true; + break; + } + } + if (!gotNonDot) { + // Special case for component of zero or more periods. Add 3 periods. + result << "..."; + for (size_t i = 0; i < valueSize; ++i) + result << '.'; + } + else { + // In case we need to escape, set to upper case hex and save the previous flags. + std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase); + + for (size_t i = 0; i < valueSize; ++i) { + uint8_t x = valuePtr[i]; + // Check for 0-9, A-Z, a-z, (+), (-), (.), (_) + if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) || + (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d || + x == 0x2e || x == 0x5f) + result << x; + else { + result << '%'; + if (x < 16) + result << '0'; + result << static_cast(x); + } + } + + // Restore. + result.flags(saveFlags); + } +} + + +Component +Component::fromNumber(uint64_t number) +{ + /// \todo Change to Tlv::NumberComponent + return nonNegativeIntegerBlock(Tlv::NameComponent, number); +} + + +uint64_t +Component::toNumber() const +{ + /// \todo Check if Component is of Tlv::NumberComponent type + return readNonNegativeInteger(static_cast(*this)); +} + + +uint64_t +Component::toVersion() const +{ + return toNumber(); +} + +uint64_t +Component::toSegment() const +{ + return toNumber(); +} + +int +Component::compare(const Component& other) const +{ + // Imitate ndn_Exclude_compareComponents. + if (value_size() < other.value_size()) + return -1; + if (value_size() > other.value_size()) + return 1; + + if (value_size() == 0) + return 0; + + // The components are equal length. Just do a byte compare. + return std::memcmp(value(), other.value(), value_size()); +} + +const Block& +Component::wireEncode() const +{ + if (this->hasWire()) + return *this; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + const_cast(*this) = buffer.block(); + return *this; +} + +void +Component::wireDecode(const Block& wire) +{ + if (wire.type() != Tlv::NameComponent) + throw Error("wireDecode name component from non name component TLV wire block"); + + *this = wire; +} + + +} // namespace name +} // namespace ndn diff --git a/src/name-component.hpp b/src/name-component.hpp index b7b529f..9af703c 100644 --- a/src/name-component.hpp +++ b/src/name-component.hpp @@ -297,17 +297,7 @@ public: * @return true if the components are equal, otherwise false. */ bool - equals(const Component& other) const - { - if (value_size() != other.value_size()) - return false; - if (value_size() == 0 /* == other.value_size()*/) - return true; - - // somehow, behavior is wrong on OSX 10.9 when component is empty - // (probably some bug in STL...) - return std::equal(value_begin(), value_end(), other.value_begin()); - } + equals(const Component& other) const; /** * @brief Compare this to the other Component using NDN canonical ordering @@ -398,44 +388,8 @@ public: // Block can be reinterpret_cast'ed as Component type. }; -inline std::ostream& -operator<<(std::ostream& os, const Component& component) -{ - component.toUri(os); - return os; -} - -inline -Component::Component() - : Block(Tlv::NameComponent) -{ -} - -inline -Component::Component(const Block& wire) - : Block(wire) -{ - if (type() != Tlv::NameComponent) - throw Error("Constructing name component from non name component TLV wire block"); -} - -inline -Component::Component(const ConstBufferPtr& buffer) - : Block(Tlv::NameComponent, buffer) -{ -} - -inline -Component::Component(const Buffer& value) - : Block(dataBlock(Tlv::NameComponent, value.buf(), value.size())) -{ -} - -inline -Component::Component(const uint8_t* value, size_t valueLen) - : Block(dataBlock(Tlv::NameComponent, value, valueLen)) -{ -} +std::ostream& +operator<<(std::ostream& os, const Component& component); template inline @@ -444,129 +398,6 @@ Component::Component(InputIterator begin, InputIterator end) { } -inline -Component::Component(const char* str) - : Block(dataBlock(Tlv::NameComponent, str, ::strlen(str))) -{ -} - -inline -Component::Component(const std::string& str) - : Block(dataBlock(Tlv::NameComponent, str.c_str(), str.size())) -{ -} - - -inline Component -Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset) -{ - std::string trimmedString(escapedString + beginOffset, escapedString + endOffset); - trim(trimmedString); - std::string value = unescape(trimmedString); - - if (value.find_first_not_of(".") == std::string::npos) { - // Special case for component of only periods. - if (value.size() <= 2) - // Zero, one or two periods is illegal. Ignore this component. - return Component(); - else - // Remove 3 periods. - return Component(reinterpret_cast(&value[3]), value.size() - 3); - } - else - return Component(reinterpret_cast(&value[0]), value.size()); -} - - -inline void -Component::toUri(std::ostream& result) const -{ - const uint8_t* valuePtr = value(); - size_t valueSize = value_size(); - - bool gotNonDot = false; - for (unsigned i = 0; i < valueSize; ++i) { - if (valuePtr[i] != 0x2e) { - gotNonDot = true; - break; - } - } - if (!gotNonDot) { - // Special case for component of zero or more periods. Add 3 periods. - result << "..."; - for (size_t i = 0; i < valueSize; ++i) - result << '.'; - } - else { - // In case we need to escape, set to upper case hex and save the previous flags. - std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase); - - for (size_t i = 0; i < valueSize; ++i) { - uint8_t x = valuePtr[i]; - // Check for 0-9, A-Z, a-z, (+), (-), (.), (_) - if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) || - (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d || - x == 0x2e || x == 0x5f) - result << x; - else { - result << '%'; - if (x < 16) - result << '0'; - result << static_cast(x); - } - } - - // Restore. - result.flags(saveFlags); - } -} - - -inline Component -Component::fromNumber(uint64_t number) -{ - /// \todo Change to Tlv::NumberComponent - return nonNegativeIntegerBlock(Tlv::NameComponent, number); -} - - -inline uint64_t -Component::toNumber() const -{ - /// \todo Check if Component is of Tlv::NumberComponent type - return readNonNegativeInteger(static_cast(*this)); -} - - -inline uint64_t -Component::toVersion() const -{ - return toNumber(); -} - -inline uint64_t -Component::toSegment() const -{ - return toNumber(); -} - -inline int -Component::compare(const Component& other) const -{ - // Imitate ndn_Exclude_compareComponents. - if (value_size() < other.value_size()) - return -1; - if (value_size() > other.value_size()) - return 1; - - if (value_size() == 0) - return 0; - - // The components are equal length. Just do a byte compare. - return std::memcmp(value(), other.value(), value_size()); -} - - template inline size_t Component::wireEncode(EncodingImpl& block) const @@ -579,31 +410,6 @@ Component::wireEncode(EncodingImpl& block) const return totalLength; } -inline const Block& -Component::wireEncode() const -{ - if (this->hasWire()) - return *this; - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - const_cast(*this) = buffer.block(); - return *this; -} - -inline void -Component::wireDecode(const Block& wire) -{ - if (wire.type() != Tlv::NameComponent) - throw Error("wireDecode name component from non name component TLV wire block"); - - *this = wire; -} - } // namespace name } // namespace ndn diff --git a/src/name.cpp b/src/name.cpp new file mode 100644 index 0000000..883cfc7 --- /dev/null +++ b/src/name.cpp @@ -0,0 +1,261 @@ +#include "name.hpp" + +namespace ndn { + +using name::Component; + +Name::Name() + : m_nameBlock(Tlv::Name) +{ +} + +Name::Name(const Block& wire) +{ + m_nameBlock = wire; + m_nameBlock.parse(); +} + +Name::Name(const char* uri) +{ + set(uri); +} + +Name::Name(const std::string& uri) +{ + set(uri.c_str()); +} + +const Component& +Name::at(ssize_t i) const +{ + if ((i >= 0 && static_cast(i) >= size()) || + (i < 0 && static_cast(-i) > size())) + throw Error("Requested component does not exist (out of bounds)"); + return get(i); +} + +std::ostream& +operator<<(std::ostream& os, const Name& name) +{ + if (name.empty()) + { + os << "/"; + } + else + { + for (Name::const_iterator i = name.begin(); i != name.end(); i++) { + os << "/"; + i->toUri(os); + } + } + return os; +} + +std::string +Name::toUri() const +{ + std::ostringstream os; + os << *this; + return os.str(); +} + +std::istream& +operator>>(std::istream& is, Name& name) +{ + std::string inputString; + is >> inputString; + name.set(inputString); + + return is; +} + + +void +Name::set(const char* uri_cstr) +{ + clear(); + + std::string uri = uri_cstr; + trim(uri); + if (uri.size() == 0) + return; + + size_t iColon = uri.find(':'); + if (iColon != std::string::npos) { + // Make sure the colon came before a '/'. + size_t iFirstSlash = uri.find('/'); + if (iFirstSlash == std::string::npos || iColon < iFirstSlash) { + // Omit the leading protocol such as ndn: + uri.erase(0, iColon + 1); + trim(uri); + } + } + + // Trim the leading slash and possibly the authority. + if (uri[0] == '/') { + if (uri.size() >= 2 && uri[1] == '/') { + // Strip the authority following "//". + size_t iAfterAuthority = uri.find('/', 2); + if (iAfterAuthority == std::string::npos) + // Unusual case: there was only an authority. + return; + else { + uri.erase(0, iAfterAuthority + 1); + trim(uri); + } + } + else { + uri.erase(0, 1); + trim(uri); + } + } + + size_t iComponentStart = 0; + + // Unescape the components. + while (iComponentStart < uri.size()) { + size_t iComponentEnd = uri.find("/", iComponentStart); + if (iComponentEnd == std::string::npos) + iComponentEnd = uri.size(); + + Component component = Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd); + // Ignore illegal components. This also gets rid of a trailing '/'. + if (!component.empty()) + append(Component(component)); + + iComponentStart = iComponentEnd + 1; + } +} + +Name& +Name::append(const Name& name) +{ + if (&name == this) + // Copying from this name, so need to make a copy first. + return append(Name(name)); + + for (size_t i = 0; i < name.size(); ++i) + append(name.at(i)); + + return *this; +} + +Name& +Name::appendVersion() +{ + appendNumber(time::toUnixTimestamp(time::system_clock::now()).count()); + return *this; +} + +Name +Name::getSubName(size_t iStartComponent, size_t nComponents) const +{ + Name result; + + size_t iEnd = iStartComponent + nComponents; + for (size_t i = iStartComponent; i < iEnd && i < size(); ++i) + result.append(at(i)); + + return result; +} + +Name +Name::getSubName(size_t iStartComponent) const +{ + Name result; + + for (size_t i = iStartComponent; i < size(); ++i) + result.append(at(i)); + + return result; +} + +bool +Name::equals(const Name& name) const +{ + if (size() != name.size()) + return false; + + for (size_t i = 0; i < size(); ++i) { + if (at(i) != name.at(i)) + return false; + } + + return true; +} + +bool +Name::isPrefixOf(const Name& name) const +{ + // This name is longer than the name we are checking it against. + if (size() > name.size()) + return false; + + // Check if at least one of given components doesn't match. + for (size_t i = 0; i < size(); ++i) { + if (at(i) != name.at(i)) + return false; + } + + return true; +} + + +int +Name::compare(const Name& other) const +{ + for (size_t i = 0; i < size() && i < other.size(); ++i) { + int comparison = at(i).compare(other.at(i)); + if (comparison == 0) + // The components at this index are equal, so check the next components. + continue; + + // Otherwise, the result is based on the components at this index. + return comparison; + } + + // The components up to min(this.size(), other.size()) are equal, so the shorter name is less. + if (size() < other.size()) + return -1; + else if (size() > other.size()) + return 1; + else + return 0; +} + +const Block& +Name::wireEncode() const +{ + if (m_nameBlock.hasWire()) + return m_nameBlock; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_nameBlock = buffer.block(); + m_nameBlock.parse(); + + return m_nameBlock; +} + +void +Name::wireDecode(const Block& wire) +{ + if (wire.type() != Tlv::Name) + throw Tlv::Error("Unexpected TLV type when decoding Name"); + + m_nameBlock = wire; + m_nameBlock.parse(); +} + +bool +Name::hasWire() const +{ + return m_nameBlock.hasWire(); +} + + +} // namespace ndn diff --git a/src/name.hpp b/src/name.hpp index 9c33528..055ebe1 100644 --- a/src/name.hpp +++ b/src/name.hpp @@ -76,10 +76,7 @@ public: /** * Create a new Name with no components. */ - Name() - : m_nameBlock(Tlv::Name) - { - } + Name(); /** * @brief Create Name object from wire block @@ -91,29 +88,19 @@ public: * @endcode */ explicit - Name(const Block& wire) - { - m_nameBlock = wire; - m_nameBlock.parse(); - } + Name(const Block& wire); /** * Parse the uri according to the NDN URI Scheme and create the name with the components. * @param uri The URI string. */ - Name(const char* uri) - { - set(uri); - } + Name(const char* uri); /** * Parse the uri according to the NDN URI Scheme and create the name with the components. * @param uri The URI string. */ - Name(const std::string& uri) - { - set(uri.c_str()); - } + Name(const std::string& uri); /** * @brief Fast encoding or block size estimation @@ -370,14 +357,7 @@ public: * @throws Name::Error if index out of bounds */ const Component& - at(ssize_t i) const - { - if ((i >= 0 && static_cast(i) >= size()) || - (i < 0 && static_cast(-i) > size())) - throw Error("Requested component does not exist (out of bounds)"); - - return get(i); - } + at(ssize_t i) const; /** * @brief Compare this to the other Name using NDN canonical ordering. @@ -525,196 +505,8 @@ private: mutable Block m_nameBlock; }; -inline std::ostream& -operator<<(std::ostream& os, const Name& name) -{ - if (name.empty()) - { - os << "/"; - } - else - { - for (Name::const_iterator i = name.begin(); i != name.end(); i++) { - os << "/"; - i->toUri(os); - } - } - return os; -} - -inline std::string -Name::toUri() const -{ - std::ostringstream os; - os << *this; - return os.str(); -} - -inline std::istream& -operator>>(std::istream& is, Name& name) -{ - std::string inputString; - is >> inputString; - name.set(inputString); - - return is; -} - - -inline void -Name::set(const char* uri_cstr) -{ - clear(); - - std::string uri = uri_cstr; - trim(uri); - if (uri.size() == 0) - return; - - size_t iColon = uri.find(':'); - if (iColon != std::string::npos) { - // Make sure the colon came before a '/'. - size_t iFirstSlash = uri.find('/'); - if (iFirstSlash == std::string::npos || iColon < iFirstSlash) { - // Omit the leading protocol such as ndn: - uri.erase(0, iColon + 1); - trim(uri); - } - } - - // Trim the leading slash and possibly the authority. - if (uri[0] == '/') { - if (uri.size() >= 2 && uri[1] == '/') { - // Strip the authority following "//". - size_t iAfterAuthority = uri.find('/', 2); - if (iAfterAuthority == std::string::npos) - // Unusual case: there was only an authority. - return; - else { - uri.erase(0, iAfterAuthority + 1); - trim(uri); - } - } - else { - uri.erase(0, 1); - trim(uri); - } - } - - size_t iComponentStart = 0; - - // Unescape the components. - while (iComponentStart < uri.size()) { - size_t iComponentEnd = uri.find("/", iComponentStart); - if (iComponentEnd == std::string::npos) - iComponentEnd = uri.size(); - - Component component = Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd); - // Ignore illegal components. This also gets rid of a trailing '/'. - if (!component.empty()) - append(Component(component)); - - iComponentStart = iComponentEnd + 1; - } -} - -inline Name& -Name::append(const Name& name) -{ - if (&name == this) - // Copying from this name, so need to make a copy first. - return append(Name(name)); - - for (size_t i = 0; i < name.size(); ++i) - append(name.at(i)); - - return *this; -} - -inline Name& -Name::appendVersion() -{ - appendNumber(time::toUnixTimestamp(time::system_clock::now()).count()); - return *this; -} - -inline Name -Name::getSubName(size_t iStartComponent, size_t nComponents) const -{ - Name result; - - size_t iEnd = iStartComponent + nComponents; - for (size_t i = iStartComponent; i < iEnd && i < size(); ++i) - result.append(at(i)); - - return result; -} - -inline Name -Name::getSubName(size_t iStartComponent) const -{ - Name result; - - for (size_t i = iStartComponent; i < size(); ++i) - result.append(at(i)); - - return result; -} - -inline bool -Name::equals(const Name& name) const -{ - if (size() != name.size()) - return false; - - for (size_t i = 0; i < size(); ++i) { - if (at(i) != name.at(i)) - return false; - } - - return true; -} - -inline bool -Name::isPrefixOf(const Name& name) const -{ - // This name is longer than the name we are checking it against. - if (size() > name.size()) - return false; - - // Check if at least one of given components doesn't match. - for (size_t i = 0; i < size(); ++i) { - if (at(i) != name.at(i)) - return false; - } - - return true; -} - - -inline int -Name::compare(const Name& other) const -{ - for (size_t i = 0; i < size() && i < other.size(); ++i) { - int comparison = at(i).compare(other.at(i)); - if (comparison == 0) - // The components at this index are equal, so check the next components. - continue; - - // Otherwise, the result is based on the components at this index. - return comparison; - } - - // The components up to min(this.size(), other.size()) are equal, so the shorter name is less. - if (size() < other.size()) - return -1; - else if (size() > other.size()) - return 1; - else - return 0; -} - - +std::ostream& +operator<<(std::ostream& os, const Name& name); template inline size_t @@ -734,40 +526,6 @@ Name::wireEncode(EncodingImpl& blk) const return totalLength; } -inline const Block& -Name::wireEncode() const -{ - if (m_nameBlock.hasWire()) - return m_nameBlock; - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - m_nameBlock = buffer.block(); - m_nameBlock.parse(); - - return m_nameBlock; -} - -inline void -Name::wireDecode(const Block& wire) -{ - if (wire.type() != Tlv::Name) - throw Tlv::Error("Unexpected TLV type when decoding Name"); - - m_nameBlock = wire; - m_nameBlock.parse(); -} - -inline bool -Name::hasWire() const -{ - return m_nameBlock.hasWire(); -} - } // namespace ndn #endif