name: Make use of naming conventions for segment, version, timestamp, and sequence number encoding
Change-Id: I99fe3965b2a4797bd14b6966b1d1d7d8fc530aef
Refs: #1761
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