name: Make use of naming conventions for segment, version, timestamp, and sequence number encoding
Change-Id: I99fe3965b2a4797bd14b6966b1d1d7d8fc530aef
Refs: #1761
diff --git a/src/data.cpp b/src/data.cpp
index d095382..77fc3c9 100644
--- a/src/data.cpp
+++ b/src/data.cpp
@@ -84,6 +84,14 @@
return totalLength;
}
+
+template size_t
+Data::wireEncode<true>(EncodingImpl<true>& block, bool unsignedPortion) const;
+
+template size_t
+Data::wireEncode<false>(EncodingImpl<false>& block, bool unsignedPortion) const;
+
+
const Block&
Data::wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const
{
diff --git a/src/exclude.hpp b/src/exclude.hpp
index 64eb653..70b60ba 100644
--- a/src/exclude.hpp
+++ b/src/exclude.hpp
@@ -25,7 +25,9 @@
#define NDN_EXCLUDE_H
#include "name-component.hpp"
+#include "encoding/encoding-buffer.hpp"
+#include <sstream>
#include <map>
namespace ndn {
diff --git a/src/interest.cpp b/src/interest.cpp
index 8bf60e3..3d3d40b 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -228,6 +228,12 @@
return totalLength;
}
+template size_t
+Interest::wireEncode<true>(EncodingImpl<true>& block) const;
+
+template size_t
+Interest::wireEncode<false>(EncodingImpl<false>& block) const;
+
const Block&
Interest::wireEncode() const
{
diff --git a/src/interest.hpp b/src/interest.hpp
index 89c5c24..e075ca7 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -29,6 +29,7 @@
#include "name.hpp"
#include "selectors.hpp"
#include "interest-filter.hpp"
+#include "util/time.hpp"
#include "management/nfd-local-control-header.hpp"
namespace ndn {
diff --git a/src/key-locator.hpp b/src/key-locator.hpp
index 33e4584..a86275d 100644
--- a/src/key-locator.hpp
+++ b/src/key-locator.hpp
@@ -23,6 +23,8 @@
#define NDN_KEY_LOCATOR_HPP
#include "encoding/block.hpp"
+#include "encoding/encoding-buffer.hpp"
+
#include "name.hpp"
namespace ndn {
diff --git a/src/management/nfd-control-parameters.hpp b/src/management/nfd-control-parameters.hpp
index 82c08ad..0ab0f84 100644
--- a/src/management/nfd-control-parameters.hpp
+++ b/src/management/nfd-control-parameters.hpp
@@ -24,6 +24,8 @@
#include "../name.hpp"
#include "../encoding/tlv-nfd.hpp"
+#include "../encoding/block-helpers.hpp"
+#include "../util/time.hpp"
namespace ndn {
namespace nfd {
diff --git a/src/management/nfd-fib-entry.hpp b/src/management/nfd-fib-entry.hpp
index 1086707..015beba 100644
--- a/src/management/nfd-fib-entry.hpp
+++ b/src/management/nfd-fib-entry.hpp
@@ -23,11 +23,13 @@
#define NDN_MANAGEMENT_NFD_FIB_ENTRY_HPP
#include "../encoding/block.hpp"
+#include "../encoding/block-helpers.hpp"
#include "../encoding/encoding-buffer.hpp"
#include "../encoding/tlv-nfd.hpp"
#include "../name.hpp"
#include <list>
+#include <sstream>
namespace ndn {
namespace nfd {
diff --git a/src/management/nfd-rib-entry.hpp b/src/management/nfd-rib-entry.hpp
index 738b8f5..d426e3f 100644
--- a/src/management/nfd-rib-entry.hpp
+++ b/src/management/nfd-rib-entry.hpp
@@ -26,6 +26,7 @@
#include "../encoding/encoding-buffer.hpp"
#include "../encoding/tlv-nfd.hpp"
#include "../name.hpp"
+#include "../util/time.hpp"
#include <list>
diff --git a/src/meta-info.hpp b/src/meta-info.hpp
index 04cded1..ed5605d 100644
--- a/src/meta-info.hpp
+++ b/src/meta-info.hpp
@@ -22,7 +22,10 @@
#ifndef NDN_META_INFO_HPP
#define NDN_META_INFO_HPP
+#include "common.hpp"
+#include "encoding/block-helpers.hpp"
#include "encoding/encoding-buffer.hpp"
+#include "util/time.hpp"
namespace ndn {
diff --git a/src/name-component.cpp b/src/name-component.cpp
new file mode 100644
index 0000000..a045766
--- /dev/null
+++ b/src/name-component.cpp
@@ -0,0 +1,342 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Jeff Thompson <jefft0@remap.ucla.edu>
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
+ */
+
+#include "name-component.hpp"
+
+#include "encoding/block-helpers.hpp"
+#include "encoding/encoding-buffer.hpp"
+#include "util/string-helper.hpp"
+
+namespace ndn {
+namespace name {
+
+Component::Component()
+ : Block(tlv::NameComponent)
+{
+}
+
+Component::Component(const Block& wire)
+ : Block(wire)
+{
+ if (type() != tlv::NameComponent)
+ throw Error("Cannot construct name::Component from not a NameComponent 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.
+ throw Error("Illegal URI (name component cannot be . or ..)");
+ else
+ // Remove 3 periods.
+ return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
+ }
+ else
+ return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
+}
+
+
+void
+Component::toUri(std::ostream& result) const
+{
+ const uint8_t* value = this->value();
+ size_t valueSize = value_size();
+
+ bool gotNonDot = false;
+ for (size_t i = 0; i < valueSize; ++i) {
+ if (value[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 = value[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<uint32_t>(x);
+ }
+ }
+
+ // Restore.
+ result.flags(saveFlags);
+ }
+}
+
+std::string
+Component::toUri() const
+{
+ std::ostringstream os;
+ toUri(os);
+ return os.str();
+}
+
+uint64_t
+Component::toNumber() const
+{
+ /// \todo Check if Component is of tlv::NumberComponent type
+ return readNonNegativeInteger(*this);
+}
+
+uint64_t
+Component::toNumberWithMarker(uint8_t marker) const
+{
+ if (empty() || value()[0] != marker)
+ throw Error("Name component does not have the requested marker");
+
+ Buffer::const_iterator valueBegin = value_begin() + 1;
+ return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
+}
+
+uint64_t
+Component::toVersion() const
+{
+ return toNumberWithMarker(VERSION_MARKER);
+}
+
+uint64_t
+Component::toSegment() const
+{
+ return toNumberWithMarker(SEGMENT_MARKER);
+}
+
+uint64_t
+Component::toSegmentOffset() const
+{
+ return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
+}
+
+time::system_clock::TimePoint
+Component::toTimestamp() const
+{
+ uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
+ return time::getUnixEpoch() + time::microseconds(value);
+}
+
+uint64_t
+Component::toSequenceNumber() const
+{
+ return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
+}
+
+
+Component
+Component::fromNumber(uint64_t number)
+{
+ /// \todo Change to tlv::NumberComponent
+ return nonNegativeIntegerBlock(tlv::NameComponent, number);
+}
+
+Component
+Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
+{
+ EncodingEstimator estimator;
+
+ size_t valueLength = estimator.prependNonNegativeInteger(number);
+ valueLength += estimator.prependByteArray(&marker, 1);
+ size_t totalLength = valueLength;
+ totalLength += estimator.prependVarNumber(valueLength);
+ totalLength += estimator.prependVarNumber(tlv::NameComponent);
+
+ EncodingBuffer encoder(totalLength, 0);
+ encoder.prependNonNegativeInteger(number);
+ encoder.prependByteArray(&marker, 1);
+ encoder.prependVarNumber(valueLength);
+ encoder.prependVarNumber(tlv::NameComponent);
+
+ return encoder.block();
+}
+
+Component
+Component::fromVersion(uint64_t version)
+{
+ return fromNumberWithMarker(VERSION_MARKER, version);
+}
+
+Component
+Component::fromSegment(uint64_t segmentNo)
+{
+ return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
+}
+
+Component
+Component::fromSegmentOffset(uint64_t offset)
+{
+ return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
+}
+
+Component
+Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
+{
+ using namespace time;
+ uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
+ return fromNumberWithMarker(TIMESTAMP_MARKER, value);
+}
+
+Component
+Component::fromSequenceNumber(uint64_t seqNo)
+{
+ return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
+}
+
+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());
+}
+
+Component
+Component::getSuccessor() const
+{
+ size_t totalLength = 0;
+ EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
+ // in unlikely case TLV length increases,
+ // EncodingBuffer will take care of that
+
+ bool isOverflow = true;
+ size_t i = value_size();
+ for (; isOverflow && i > 0; i--) {
+ uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
+ totalLength += encoder.prependByte(newValue);
+ isOverflow = (newValue == 0);
+ }
+ totalLength += encoder.prependByteArray(value(), i);
+
+ if (isOverflow) {
+ // new name components has to be extended
+ totalLength += encoder.appendByte(0);
+ }
+
+ totalLength += encoder.prependVarNumber(totalLength);
+ totalLength += encoder.prependVarNumber(tlv::NameComponent);
+
+ return encoder.block();
+}
+
+
+template<bool T>
+size_t
+Component::wireEncode(EncodingImpl<T>& block) const
+{
+ size_t totalLength = 0;
+ if (value_size() > 0)
+ totalLength += block.prependByteArray(value(), value_size());
+ totalLength += block.prependVarNumber(value_size());
+ totalLength += block.prependVarNumber(tlv::NameComponent);
+ return totalLength;
+}
+
+template size_t
+Component::wireEncode<true>(EncodingImpl<true>& block) const;
+
+template size_t
+Component::wireEncode<false>(EncodingImpl<false>& block) const;
+
+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<Component&>(*this) = buffer.block();
+ return *this;
+}
+
+void
+Component::wireDecode(const Block& wire)
+{
+ if (wire.type() != tlv::NameComponent)
+ throw Error("name::Component::wireDecode called on not a NameComponent TLV wire block");
+
+ *this = wire;
+}
+
+} // namespace name
+} // namespace ndn
diff --git a/src/name-component.hpp b/src/name-component.hpp
index a9be6a8..7213f9a 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -28,13 +28,22 @@
#include "common.hpp"
#include "encoding/block.hpp"
-#include "encoding/block-helpers.hpp"
-#include "encoding/encoding-buffer.hpp"
-#include "util/string-helper.hpp"
+#include "util/time.hpp"
namespace ndn {
namespace name {
+/// @brief Segment marker for NDN naming conventions
+static const uint8_t SEGMENT_MARKER = 0x00;
+/// @brief Segment offset marker for NDN naming conventions
+static const uint8_t SEGMENT_OFFSET_MARKER = 0xFB;
+/// @brief Version marker for NDN naming conventions
+static const uint8_t VERSION_MARKER = 0xFD;
+/// @brief Timestamp marker for NDN naming conventions
+static const uint8_t TIMESTAMP_MARKER = 0xFC;
+/// @brief Sequence number marker for NDN naming conventions
+static const uint8_t SEQUENCE_NUMBER_MARKER = 0xFE;
+
/**
* @brief Component holds a read-only name component value.
*/
@@ -244,12 +253,7 @@
* @return The escaped string
*/
std::string
- toUri() const
- {
- std::ostringstream os;
- toUri(os);
- return os.str();
- }
+ toUri() const;
/**
* @brief Interpret this name component as nonNegativeInteger
@@ -262,18 +266,74 @@
toNumber() const;
/**
- * @brief An alias for toNumber()
+ * @brief Interpret this name component as NameComponentWithMarker
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @param marker 1-byte octet of the marker
+ * @return The integer number.
+ * @throws Error if name component does not have the specified marker.
+ * tlv::Error if format does not follow NameComponentWithMarker specification.
+ */
+ uint64_t
+ toNumberWithMarker(uint8_t marker) const;
+
+ /**
+ * @brief Interpret as version component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @throws Error if name component does not have the specified marker.
+ * tlv::Error if format does not follow NameComponentWithMarker specification.
*/
uint64_t
toVersion() const;
/**
- * @brief An alias for toNumber()
+ * @brief Interpret as segment number component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @throws Error if name component does not have the specified marker.
+ * tlv::Error if format does not follow NameComponentWithMarker specification.
*/
uint64_t
toSegment() const;
/**
+ * @brief Interpret as segment offset component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @throws Error if name component does not have the specified marker.
+ * tlv::Error if format does not follow NameComponentWithMarker specification.
+ */
+ uint64_t
+ toSegmentOffset() const;
+
+ /**
+ * @brief Interpret as timestamp component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @throws Error if name component does not have the specified marker.
+ * tlv::Error if format does not follow NameComponentWithMarker specification.
+ */
+ time::system_clock::TimePoint
+ toTimestamp() const;
+
+ /**
+ * @brief Interpret as sequence number component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @throws Error if name component does not have the specified marker.
+ * tlv::Error if format does not follow NameComponentWithMarker specification.
+ */
+ uint64_t
+ toSequenceNumber() const;
+
+ /**
* @brief Create a component encoded as nonNegativeInteger
*
* @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
@@ -284,6 +344,70 @@
static Component
fromNumber(uint64_t number);
+ /**
+ * @brief Create a component encoded as NameComponentWithMarker
+ *
+ * NameComponentWithMarker is defined as:
+ *
+ * NameComponentWithMarker ::= NAME-COMPONENT-TYPE TLV-LEGTH
+ * Marker
+ * includedNonNegativeInteger
+ * Marker ::= BYTE
+ * includedNonNegativeInteger ::= BYTE{1,2,4,8}
+ * NDN-TLV := TLV-TYPE TLV-LENGTH TLV-VALUE?
+ * TLV-TYPE := VAR-NUMBER
+ * TLV-LENGTH := VAR-NUMBER
+ * TLV-VALUE := BYTE+
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @param marker 1-byte marker octet
+ * @param number The non-negative number
+ * @return The component value.
+ */
+ static Component
+ fromNumberWithMarker(uint8_t marker, uint64_t number);
+
+ /**
+ * @brief Create version component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ static Component
+ fromVersion(uint64_t version);
+
+ /**
+ * @brief Create segment number component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ static Component
+ fromSegment(uint64_t segmentNo);
+
+ /**
+ * @brief Create segment offset component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ static Component
+ fromSegmentOffset(uint64_t offset);
+
+ /**
+ * @brief Create sequence number component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ static Component
+ fromTimestamp(const time::system_clock::TimePoint& timePoint);
+
+ /**
+ * @brief Create sequence number component using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ static Component
+ fromSequenceNumber(uint64_t seqNo);
+
bool
empty() const
{
@@ -408,38 +532,6 @@
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))
-{
-}
-
template<class InputIterator>
inline
Component::Component(InputIterator begin, InputIterator end)
@@ -447,195 +539,6 @@
{
}
-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<const uint8_t*>(&value[3]), value.size() - 3);
- }
- else
- return Component(reinterpret_cast<const uint8_t*>(&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<unsigned int>(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<const Block&>(*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());
-}
-
-inline Component
-Component::getSuccessor() const
-{
- size_t totalLength = 0;
- EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
- // in unlikely case TLV length changes more,
- // EncodingBuffer will take care of that
-
- bool isOverflow = true;
- size_t i = value_size();
- for (; isOverflow && i > 0; i--) {
- uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
- totalLength += encoder.prependByte(newValue);
- isOverflow = (newValue == 0);
- }
- totalLength += encoder.prependByteArray(value(), i);
-
- if (isOverflow) {
- // new name components has to be extended
- totalLength += encoder.appendByte(0);
- }
-
- totalLength += encoder.prependVarNumber(totalLength);
- totalLength += encoder.prependVarNumber(tlv::NameComponent);
-
- return encoder.block();
-}
-
-
-template<bool T>
-inline size_t
-Component::wireEncode(EncodingImpl<T>& block) const
-{
- size_t totalLength = 0;
- if (value_size() > 0)
- totalLength += block.prependByteArray(value(), value_size());
- totalLength += block.prependVarNumber(value_size());
- totalLength += block.prependVarNumber(tlv::NameComponent);
- 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<Component&>(*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..ea0015b
--- /dev/null
+++ b/src/name.cpp
@@ -0,0 +1,336 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Jeff Thompson <jefft0@remap.ucla.edu>
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
+ */
+
+#include "name.hpp"
+
+#include "util/time.hpp"
+#include "util/string-helper.hpp"
+#include "encoding/block.hpp"
+#include "encoding/encoding-buffer.hpp"
+
+namespace ndn {
+
+template<bool T>
+size_t
+Name::wireEncode(EncodingImpl<T>& encoder) const
+{
+ size_t totalLength = 0;
+
+ for (const_reverse_iterator i = rbegin(); i != rend(); ++i)
+ {
+ totalLength += i->wireEncode(encoder);
+ }
+
+ totalLength += encoder.prependVarNumber(totalLength);
+ totalLength += encoder.prependVarNumber(tlv::Name);
+ return totalLength;
+}
+
+template size_t
+Name::wireEncode<true>(EncodingImpl<true>& estimator) const;
+
+template size_t
+Name::wireEncode<false>(EncodingImpl<false>& encoder) const;
+
+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();
+}
+
+void
+Name::set(const char* uriOrig)
+{
+ clear();
+
+ std::string uri = uriOrig;
+ 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;
+ }
+}
+
+std::string
+Name::toUri() const
+{
+ std::ostringstream os;
+ os << *this;
+ return os.str();
+}
+
+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::appendNumber(uint64_t number)
+{
+ m_nameBlock.push_back(Component::fromNumber(number));
+ return *this;
+}
+
+Name&
+Name::appendNumberWithMarker(uint8_t marker, uint64_t number)
+{
+ m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number));
+ return *this;
+}
+
+Name&
+Name::appendVersion(uint64_t version)
+{
+ m_nameBlock.push_back(Component::fromVersion(version));
+ return *this;
+}
+
+Name&
+Name::appendVersion()
+{
+ appendNumber(time::toUnixTimestamp(time::system_clock::now()).count());
+ return *this;
+}
+
+Name&
+Name::appendSegment(uint64_t segmentNo)
+{
+ m_nameBlock.push_back(Component::fromSegment(segmentNo));
+ return *this;
+}
+
+Name&
+Name::appendSegmentOffset(uint64_t offset)
+{
+ m_nameBlock.push_back(Component::fromSegmentOffset(offset));
+ return *this;
+}
+
+Name&
+Name::appendTimestamp(const time::system_clock::TimePoint& timePoint)
+{
+ m_nameBlock.push_back(Component::fromTimestamp(timePoint));
+ return *this;
+}
+
+Name&
+Name::appendSequenceNumber(uint64_t seqNo)
+{
+ m_nameBlock.push_back(Component::fromSequenceNumber(seqNo));
+ 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;
+}
+
+Name
+Name::getSuccessor() const
+{
+ if (empty()) {
+ static uint8_t firstValue[] = { 0 };
+ Name firstName;
+ firstName.append(firstValue, 1);
+ return firstName;
+ }
+
+ return getPrefix(-1).append(get(-1).getSuccessor());
+}
+
+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 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;
+}
+
+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::istream&
+operator>>(std::istream& is, Name& name)
+{
+ std::string inputString;
+ is >> inputString;
+ name.set(inputString);
+
+ return is;
+}
+
+} // namespace ndn
diff --git a/src/name.hpp b/src/name.hpp
index 0e8c840..f4b1411 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -28,10 +28,6 @@
#include "common.hpp"
#include "name-component.hpp"
-#include "util/time.hpp"
-
-#include "encoding/block.hpp"
-#include "encoding/encoding-buffer.hpp"
#include <boost/iterator/reverse_iterator.hpp>
@@ -233,7 +229,9 @@
getSubName(size_t iStartComponent, size_t nComponents) const;
/**
- * Get a new name, constructed as a subset of components starting at iStartComponent until the end of the name.
+ * @brief Get a new name, constructed as a subset of components starting at
+ * iStartComponent until the end of the name.
+ *
* @param iStartComponent The index if the first component to get.
* @return A new name.
*/
@@ -241,13 +239,15 @@
getSubName(size_t iStartComponent) const;
/**
- * Return a new Name with the first nComponents components of this Name.
- * @param nComponents The number of prefix components. If nComponents is -N then return the prefix up
- * to name.size() - N. For example getPrefix(-1) returns the name without the final component.
+ * @brief Return a new Name with the first nComponents components of this Name.
+ *
+ * @param nComponents The number of prefix components. If nComponents is -N then return
+ * the prefix up to name.size() - N. For example getPrefix(-1)
+ * returns the name without the final component.
* @return A new Name.
*/
Name
- getPrefix(int nComponents) const
+ getPrefix(ssize_t nComponents) const
{
if (nComponents < 0)
return getSubName(0, m_nameBlock.elements_size() + nComponents);
@@ -271,41 +271,87 @@
* @return This name so that you can chain calls to append.
*/
Name&
- appendNumber(uint64_t number)
- {
- m_nameBlock.push_back(Component::fromNumber(number));
- return *this;
- }
+ appendNumber(uint64_t number);
/**
- * @brief An alias for appendNumber(uint64_t)
+ * @brief Create a component encoded as NameComponentWithMarker
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @param marker 1-byte marker octet
+ * @param number The non-negative number
*/
Name&
- appendVersion(uint64_t number)
- {
- return appendNumber(number);
- }
+ appendNumberWithMarker(uint8_t marker, uint64_t number);
/**
- * @brief Append a component with the encoded version number (current UNIX timestamp
- * in milliseconds)
+ * @brief Append version using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendVersion(uint64_t version);
+
+ /**
+ * @brief Append version using NDN naming conventions based on current UNIX timestamp
+ * in milliseconds
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
*/
Name&
appendVersion();
/**
- * @brief An alias for appendNumber(uint64_t)
+ * @brief Append segment number (sequential) using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
*/
Name&
- appendSegment(uint64_t number)
- {
- return appendNumber(number);
- }
+ appendSegment(uint64_t segmentNo);
/**
- * @brief get the successor of a name
- * successor of a name is defined that its last component is
- * advanced next possible value of last component of original name
+ * @brief Append segment byte offset using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSegmentOffset(uint64_t offset);
+
+ /**
+ * @brief Append timestamp using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendTimestamp(const time::system_clock::TimePoint& timePoint = time::system_clock::now());
+
+ /**
+ * @brief Append sequence number using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSequenceNumber(uint64_t seqNo);
+
+ /**
+ * @brief Get the successor of a name
+ *
+ * The successor of a name is defined as follows:
+ *
+ * N represents the set of NDN Names, and X,Y ∈ N.
+ * Operator < is defined by canonical order on N.
+ * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ N s.t. X < Z < Y.
+ *
+ * In plain words, successor of a name is the same name, but with its last component
+ * advanced to a next possible value.
+ *
+ * Examples:
+ *
+ * - successor for / is /%00
+ * - successor for /%00%01/%01%02 is /%00%01/%01%03
+ * - successor for /%00%01/%01%FF is /%00%01/%02%00
+ * - successor for /%00%01/%FF%FF is /%00%01/%00%00%00
+ *
* @return a new name
*/
Name
@@ -320,9 +366,12 @@
equals(const Name& name) const;
/**
- * Check if the N components of this name are the same as the first N components of the given name.
+ * @brief Check if the N components of this name are the same as the first N components
+ * of the given name.
+ *
* @param name The Name to check.
- * @return true if this matches the given name, otherwise false. This always returns true if this name is empty.
+ * @return true if this matches the given name, otherwise false. This always returns
+ * true if this name is empty.
*/
bool
isPrefixOf(const Name& name) const;
@@ -534,255 +583,11 @@
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;
-}
+std::ostream&
+operator<<(std::ostream& os, const Name& name);
-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 Name
-Name::getSuccessor() const
-{
- if (empty()) {
- static uint8_t firstValue[] = { 0 };
- Name firstName;
- firstName.append(firstValue, 1);
- return firstName;
- }
-
- return getPrefix(-1).append(get(-1).getSuccessor());
-}
-
-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;
-}
-
-
-
-template<bool T>
-inline size_t
-Name::wireEncode(EncodingImpl<T>& blk) const
-{
- size_t totalLength = 0;
-
- for (const_reverse_iterator i = rbegin();
- i != rend();
- ++i)
- {
- totalLength += i->wireEncode(blk);
- }
-
- totalLength += blk.prependVarNumber(totalLength);
- totalLength += blk.prependVarNumber(tlv::Name);
- 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();
-}
+std::istream&
+operator>>(std::istream& is, Name& name);
inline bool
Name::hasWire() const
diff --git a/src/selectors.hpp b/src/selectors.hpp
index e09acea..c4fcb42 100644
--- a/src/selectors.hpp
+++ b/src/selectors.hpp
@@ -26,6 +26,7 @@
#include "key-locator.hpp"
#include "exclude.hpp"
#include "encoding/encoding-buffer.hpp"
+#include "encoding/block-helpers.hpp"
namespace ndn {
diff --git a/src/signature-info.cpp b/src/signature-info.cpp
index 469bdee..1e40b1f 100644
--- a/src/signature-info.cpp
+++ b/src/signature-info.cpp
@@ -20,6 +20,8 @@
*/
#include "signature-info.hpp"
+#include "encoding/block-helpers.hpp"
+
#include <boost/lexical_cast.hpp>
namespace ndn {