blob: d80fecf17ffde15fd9bf94ae7a2037fec3f6048d [file] [log] [blame]
Alexander Afanasyev15f67312014-07-22 15:11:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi71ff2312017-07-12 13:32:50 +00002/*
Davide Pesaventodd461432017-01-28 21:47:26 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Alexander Afanasyev15f67312014-07-22 15:11:09 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 *
21 * @author Jeff Thompson <jefft0@remap.ucla.edu>
22 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
23 * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
24 */
25
26#include "name.hpp"
27
Alexander Afanasyev15f67312014-07-22 15:11:09 -070028#include "encoding/block.hpp"
29#include "encoding/encoding-buffer.hpp"
Junxiao Shi71ff2312017-07-12 13:32:50 +000030#include "util/time.hpp"
Alexander Afanasyev15f67312014-07-22 15:11:09 -070031
Junxiao Shi71ff2312017-07-12 13:32:50 +000032#include <sstream>
Davide Pesaventodd461432017-01-28 21:47:26 -050033#include <boost/algorithm/string/trim.hpp>
Yingdi Yu90e23582014-11-06 14:21:04 -080034#include <boost/functional/hash.hpp>
Junxiao Shiadc334e2017-07-14 20:28:28 +000035#include <boost/range/adaptor/reversed.hpp>
36#include <boost/range/concepts.hpp>
Yingdi Yu90e23582014-11-06 14:21:04 -080037
Alexander Afanasyev15f67312014-07-22 15:11:09 -070038namespace ndn {
39
Junxiao Shic2b8d242014-11-04 08:35:29 -070040BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
41BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070042BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Name>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070043BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
Junxiao Shiadc334e2017-07-14 20:28:28 +000044BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::iterator>));
45BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_iterator>));
46BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::reverse_iterator>));
47BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_reverse_iterator>));
48BOOST_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<Name>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070049static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
50 "Name::Error must inherit from tlv::Error");
51
Junxiao Shia6452ac2015-01-23 11:21:06 -070052const size_t Name::npos = std::numeric_limits<size_t>::max();
53
Junxiao Shi71ff2312017-07-12 13:32:50 +000054// ---- constructors, encoding, decoding ----
55
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080056Name::Name()
Junxiao Shi71ff2312017-07-12 13:32:50 +000057 : m_wire(tlv::Name)
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080058{
59}
60
61Name::Name(const Block& wire)
Junxiao Shiadc334e2017-07-14 20:28:28 +000062 : m_wire(wire)
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080063{
Junxiao Shi71ff2312017-07-12 13:32:50 +000064 m_wire.parse();
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080065}
66
67Name::Name(const char* uri)
Junxiao Shi3188c4032016-07-18 20:53:56 +000068 : Name(std::string(uri))
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080069{
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080070}
71
Junxiao Shi3188c4032016-07-18 20:53:56 +000072Name::Name(std::string uri)
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080073{
Davide Pesaventodd461432017-01-28 21:47:26 -050074 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000075 if (uri.empty())
76 return;
77
78 size_t iColon = uri.find(':');
79 if (iColon != std::string::npos) {
80 // Make sure the colon came before a '/'.
81 size_t iFirstSlash = uri.find('/');
82 if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
83 // Omit the leading protocol such as ndn:
84 uri.erase(0, iColon + 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050085 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000086 }
87 }
88
89 // Trim the leading slash and possibly the authority.
90 if (uri[0] == '/') {
91 if (uri.size() >= 2 && uri[1] == '/') {
92 // Strip the authority following "//".
93 size_t iAfterAuthority = uri.find('/', 2);
94 if (iAfterAuthority == std::string::npos)
95 // Unusual case: there was only an authority.
96 return;
97 else {
98 uri.erase(0, iAfterAuthority + 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050099 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +0000100 }
101 }
102 else {
103 uri.erase(0, 1);
Davide Pesaventodd461432017-01-28 21:47:26 -0500104 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +0000105 }
106 }
107
108 size_t iComponentStart = 0;
109
110 // Unescape the components.
111 while (iComponentStart < uri.size()) {
112 size_t iComponentEnd = uri.find("/", iComponentStart);
113 if (iComponentEnd == std::string::npos)
114 iComponentEnd = uri.size();
115
116 append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
117 iComponentStart = iComponentEnd + 1;
118 }
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800119}
120
Junxiao Shi71ff2312017-07-12 13:32:50 +0000121std::string
122Name::toUri() const
Alexander Afanasyev4f512fb2016-05-18 10:47:53 -0700123{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000124 std::ostringstream os;
125 os << *this;
126 return os.str();
Alexander Afanasyev4f512fb2016-05-18 10:47:53 -0700127}
128
Alexander Afanasyev74633892015-02-08 18:08:46 -0800129template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700130size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800131Name::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700132{
133 size_t totalLength = 0;
Junxiao Shiadc334e2017-07-14 20:28:28 +0000134 for (const Component& comp : *this | boost::adaptors::reversed) {
135 totalLength += comp.wireEncode(encoder);
Junxiao Shi71ff2312017-07-12 13:32:50 +0000136 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700137
138 totalLength += encoder.prependVarNumber(totalLength);
139 totalLength += encoder.prependVarNumber(tlv::Name);
140 return totalLength;
141}
142
Davide Pesavento88a0d812017-08-19 21:31:42 -0400143NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Name);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700144
145const Block&
146Name::wireEncode() const
147{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000148 if (m_wire.hasWire())
149 return m_wire;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700150
151 EncodingEstimator estimator;
152 size_t estimatedSize = wireEncode(estimator);
153
154 EncodingBuffer buffer(estimatedSize, 0);
155 wireEncode(buffer);
156
Junxiao Shi71ff2312017-07-12 13:32:50 +0000157 m_wire = buffer.block();
158 m_wire.parse();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700159
Junxiao Shi71ff2312017-07-12 13:32:50 +0000160 return m_wire;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700161}
162
163void
164Name::wireDecode(const Block& wire)
165{
166 if (wire.type() != tlv::Name)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700167 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700168
Junxiao Shi71ff2312017-07-12 13:32:50 +0000169 m_wire = wire;
170 m_wire.parse();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700171}
172
Junxiao Shi71ff2312017-07-12 13:32:50 +0000173Name
174Name::deepCopy() const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700175{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000176 Name copiedName(*this);
177 copiedName.m_wire.resetWire();
178 copiedName.wireEncode(); // "compress" the underlying buffer
179 return copiedName;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700180}
181
Junxiao Shi71ff2312017-07-12 13:32:50 +0000182// ---- accessors ----
183
184const name::Component&
185Name::at(ssize_t i) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700186{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000187 if (i < 0) {
188 i = size() + i;
189 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700190
Junxiao Shi71ff2312017-07-12 13:32:50 +0000191 if (i < 0 || static_cast<size_t>(i) >= size()) {
192 BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)"));
193 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700194
Junxiao Shi71ff2312017-07-12 13:32:50 +0000195 return reinterpret_cast<const Component&>(m_wire.elements()[i]);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700196}
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700197
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400198PartialName
199Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700200{
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400201 PartialName result;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700202
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400203 ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
Junxiao Shia6452ac2015-01-23 11:21:06 -0700204 size_t iEnd = this->size();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700205
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400206 iStart = std::max(iStart, static_cast<ssize_t>(0));
207
208 if (nComponents != npos)
209 iEnd = std::min(this->size(), iStart + nComponents);
210
211 for (size_t i = iStart; i < iEnd; ++i)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700212 result.append(at(i));
213
214 return result;
215}
216
Junxiao Shi71ff2312017-07-12 13:32:50 +0000217// ---- modifiers ----
218
219Name&
220Name::appendVersion()
221{
222 return appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
223}
224
225Name&
226Name::appendTimestamp()
227{
228 return appendTimestamp(time::system_clock::now());
229}
230
231Name&
232Name::append(const PartialName& name)
233{
234 if (&name == this)
235 // Copying from this name, so need to make a copy first.
236 return append(PartialName(name));
237
238 for (size_t i = 0; i < name.size(); ++i)
239 append(name.at(i));
240
241 return *this;
242}
243
244// ---- algorithms ----
245
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700246Name
247Name::getSuccessor() const
248{
249 if (empty()) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000250 static uint8_t firstValue[] {0};
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700251 Name firstName;
252 firstName.append(firstValue, 1);
253 return firstName;
254 }
255
256 return getPrefix(-1).append(get(-1).getSuccessor());
257}
258
259bool
Junxiao Shi71ff2312017-07-12 13:32:50 +0000260Name::isPrefixOf(const Name& other) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700261{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000262 // This name is longer than the name we are checking against.
263 if (size() > other.size())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700264 return false;
265
Junxiao Shi71ff2312017-07-12 13:32:50 +0000266 // Check if at least one of given components doesn't match.
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700267 for (size_t i = 0; i < size(); ++i) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000268 if (get(i) != other.get(i))
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700269 return false;
270 }
271
272 return true;
273}
274
275bool
Junxiao Shi71ff2312017-07-12 13:32:50 +0000276Name::equals(const Name& other) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700277{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000278 if (size() != other.size())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700279 return false;
280
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700281 for (size_t i = 0; i < size(); ++i) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000282 if (get(i) != other.get(i))
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700283 return false;
284 }
285
286 return true;
287}
288
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700289int
Junxiao Shia6452ac2015-01-23 11:21:06 -0700290Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700291{
Junxiao Shia6452ac2015-01-23 11:21:06 -0700292 count1 = std::min(count1, this->size() - pos1);
293 count2 = std::min(count2, other.size() - pos2);
294 size_t count = std::min(count1, count2);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700295
Junxiao Shia6452ac2015-01-23 11:21:06 -0700296 for (size_t i = 0; i < count; ++i) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000297 int comp = get(pos1 + i).compare(other.get(pos2 + i));
Junxiao Shia6452ac2015-01-23 11:21:06 -0700298 if (comp != 0) { // i-th component differs
299 return comp;
300 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700301 }
Junxiao Shia6452ac2015-01-23 11:21:06 -0700302 // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
Joao Pereiraaa8fd162015-06-05 16:35:15 -0400303 return count1 - count2;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700304}
305
Junxiao Shi71ff2312017-07-12 13:32:50 +0000306// ---- stream operators ----
307
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700308std::ostream&
309operator<<(std::ostream& os, const Name& name)
310{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000311 if (name.empty()) {
312 os << "/";
313 }
314 else {
315 for (const auto& component : name) {
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700316 os << "/";
Junxiao Shi71ff2312017-07-12 13:32:50 +0000317 component.toUri(os);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700318 }
Junxiao Shi71ff2312017-07-12 13:32:50 +0000319 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700320 return os;
321}
322
323std::istream&
324operator>>(std::istream& is, Name& name)
325{
326 std::string inputString;
327 is >> inputString;
Alexander Afanasyev66ca2032015-12-04 13:17:02 -0800328 name = Name(inputString);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700329
330 return is;
331}
332
333} // namespace ndn
Yingdi Yu90e23582014-11-06 14:21:04 -0800334
335namespace std {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000336
Yingdi Yu90e23582014-11-06 14:21:04 -0800337size_t
338hash<ndn::Name>::operator()(const ndn::Name& name) const
339{
340 return boost::hash_range(name.wireEncode().wire(),
341 name.wireEncode().wire() + name.wireEncode().size());
342}
343
344} // namespace std