blob: 58b1cc353890523ce9554bda6a268b576aea6d88 [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>
35
Alexander Afanasyev15f67312014-07-22 15:11:09 -070036namespace ndn {
37
Junxiao Shic2b8d242014-11-04 08:35:29 -070038BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
39BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070040BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Name>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070041BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
42static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
43 "Name::Error must inherit from tlv::Error");
44
Junxiao Shia6452ac2015-01-23 11:21:06 -070045const size_t Name::npos = std::numeric_limits<size_t>::max();
46
Junxiao Shi71ff2312017-07-12 13:32:50 +000047// ---- constructors, encoding, decoding ----
48
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080049Name::Name()
Junxiao Shi71ff2312017-07-12 13:32:50 +000050 : m_wire(tlv::Name)
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080051{
52}
53
54Name::Name(const Block& wire)
55{
Junxiao Shi71ff2312017-07-12 13:32:50 +000056 m_wire = wire;
57 m_wire.parse();
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080058}
59
60Name::Name(const char* uri)
Junxiao Shi3188c4032016-07-18 20:53:56 +000061 : Name(std::string(uri))
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080062{
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080063}
64
Junxiao Shi3188c4032016-07-18 20:53:56 +000065Name::Name(std::string uri)
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080066{
Davide Pesaventodd461432017-01-28 21:47:26 -050067 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000068 if (uri.empty())
69 return;
70
71 size_t iColon = uri.find(':');
72 if (iColon != std::string::npos) {
73 // Make sure the colon came before a '/'.
74 size_t iFirstSlash = uri.find('/');
75 if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
76 // Omit the leading protocol such as ndn:
77 uri.erase(0, iColon + 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050078 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000079 }
80 }
81
82 // Trim the leading slash and possibly the authority.
83 if (uri[0] == '/') {
84 if (uri.size() >= 2 && uri[1] == '/') {
85 // Strip the authority following "//".
86 size_t iAfterAuthority = uri.find('/', 2);
87 if (iAfterAuthority == std::string::npos)
88 // Unusual case: there was only an authority.
89 return;
90 else {
91 uri.erase(0, iAfterAuthority + 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050092 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000093 }
94 }
95 else {
96 uri.erase(0, 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050097 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000098 }
99 }
100
101 size_t iComponentStart = 0;
102
103 // Unescape the components.
104 while (iComponentStart < uri.size()) {
105 size_t iComponentEnd = uri.find("/", iComponentStart);
106 if (iComponentEnd == std::string::npos)
107 iComponentEnd = uri.size();
108
109 append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
110 iComponentStart = iComponentEnd + 1;
111 }
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800112}
113
Junxiao Shi71ff2312017-07-12 13:32:50 +0000114std::string
115Name::toUri() const
Alexander Afanasyev4f512fb2016-05-18 10:47:53 -0700116{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000117 std::ostringstream os;
118 os << *this;
119 return os.str();
Alexander Afanasyev4f512fb2016-05-18 10:47:53 -0700120}
121
Alexander Afanasyev74633892015-02-08 18:08:46 -0800122template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700123size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800124Name::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700125{
126 size_t totalLength = 0;
127
Junxiao Shi71ff2312017-07-12 13:32:50 +0000128 for (const_reverse_iterator i = rbegin(); i != rend(); ++i) {
129 totalLength += i->wireEncode(encoder);
130 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700131
132 totalLength += encoder.prependVarNumber(totalLength);
133 totalLength += encoder.prependVarNumber(tlv::Name);
134 return totalLength;
135}
136
137template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700138Name::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700139
140template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800141Name::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700142
143const Block&
144Name::wireEncode() const
145{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000146 if (m_wire.hasWire())
147 return m_wire;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700148
149 EncodingEstimator estimator;
150 size_t estimatedSize = wireEncode(estimator);
151
152 EncodingBuffer buffer(estimatedSize, 0);
153 wireEncode(buffer);
154
Junxiao Shi71ff2312017-07-12 13:32:50 +0000155 m_wire = buffer.block();
156 m_wire.parse();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700157
Junxiao Shi71ff2312017-07-12 13:32:50 +0000158 return m_wire;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700159}
160
161void
162Name::wireDecode(const Block& wire)
163{
164 if (wire.type() != tlv::Name)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700165 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700166
Junxiao Shi71ff2312017-07-12 13:32:50 +0000167 m_wire = wire;
168 m_wire.parse();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700169}
170
Junxiao Shi71ff2312017-07-12 13:32:50 +0000171Name
172Name::deepCopy() const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700173{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000174 Name copiedName(*this);
175 copiedName.m_wire.resetWire();
176 copiedName.wireEncode(); // "compress" the underlying buffer
177 return copiedName;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700178}
179
Junxiao Shi71ff2312017-07-12 13:32:50 +0000180// ---- accessors ----
181
182const name::Component&
183Name::at(ssize_t i) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700184{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000185 if (i < 0) {
186 i = size() + i;
187 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700188
Junxiao Shi71ff2312017-07-12 13:32:50 +0000189 if (i < 0 || static_cast<size_t>(i) >= size()) {
190 BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)"));
191 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700192
Junxiao Shi71ff2312017-07-12 13:32:50 +0000193 return reinterpret_cast<const Component&>(m_wire.elements()[i]);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700194}
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700195
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400196PartialName
197Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700198{
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400199 PartialName result;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700200
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400201 ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
Junxiao Shia6452ac2015-01-23 11:21:06 -0700202 size_t iEnd = this->size();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700203
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400204 iStart = std::max(iStart, static_cast<ssize_t>(0));
205
206 if (nComponents != npos)
207 iEnd = std::min(this->size(), iStart + nComponents);
208
209 for (size_t i = iStart; i < iEnd; ++i)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700210 result.append(at(i));
211
212 return result;
213}
214
Junxiao Shi71ff2312017-07-12 13:32:50 +0000215// ---- modifiers ----
216
217Name&
218Name::appendVersion()
219{
220 return appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
221}
222
223Name&
224Name::appendTimestamp()
225{
226 return appendTimestamp(time::system_clock::now());
227}
228
229Name&
230Name::append(const PartialName& name)
231{
232 if (&name == this)
233 // Copying from this name, so need to make a copy first.
234 return append(PartialName(name));
235
236 for (size_t i = 0; i < name.size(); ++i)
237 append(name.at(i));
238
239 return *this;
240}
241
242// ---- algorithms ----
243
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700244Name
245Name::getSuccessor() const
246{
247 if (empty()) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000248 static uint8_t firstValue[] {0};
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700249 Name firstName;
250 firstName.append(firstValue, 1);
251 return firstName;
252 }
253
254 return getPrefix(-1).append(get(-1).getSuccessor());
255}
256
257bool
Junxiao Shi71ff2312017-07-12 13:32:50 +0000258Name::isPrefixOf(const Name& other) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700259{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000260 // This name is longer than the name we are checking against.
261 if (size() > other.size())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700262 return false;
263
Junxiao Shi71ff2312017-07-12 13:32:50 +0000264 // Check if at least one of given components doesn't match.
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700265 for (size_t i = 0; i < size(); ++i) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000266 if (get(i) != other.get(i))
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700267 return false;
268 }
269
270 return true;
271}
272
273bool
Junxiao Shi71ff2312017-07-12 13:32:50 +0000274Name::equals(const Name& other) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700275{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000276 if (size() != other.size())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700277 return false;
278
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700279 for (size_t i = 0; i < size(); ++i) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000280 if (get(i) != other.get(i))
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700281 return false;
282 }
283
284 return true;
285}
286
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700287int
Junxiao Shia6452ac2015-01-23 11:21:06 -0700288Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700289{
Junxiao Shia6452ac2015-01-23 11:21:06 -0700290 count1 = std::min(count1, this->size() - pos1);
291 count2 = std::min(count2, other.size() - pos2);
292 size_t count = std::min(count1, count2);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700293
Junxiao Shia6452ac2015-01-23 11:21:06 -0700294 for (size_t i = 0; i < count; ++i) {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000295 int comp = get(pos1 + i).compare(other.get(pos2 + i));
Junxiao Shia6452ac2015-01-23 11:21:06 -0700296 if (comp != 0) { // i-th component differs
297 return comp;
298 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700299 }
Junxiao Shia6452ac2015-01-23 11:21:06 -0700300 // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
Joao Pereiraaa8fd162015-06-05 16:35:15 -0400301 return count1 - count2;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700302}
303
Junxiao Shi71ff2312017-07-12 13:32:50 +0000304// ---- stream operators ----
305
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700306std::ostream&
307operator<<(std::ostream& os, const Name& name)
308{
Junxiao Shi71ff2312017-07-12 13:32:50 +0000309 if (name.empty()) {
310 os << "/";
311 }
312 else {
313 for (const auto& component : name) {
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700314 os << "/";
Junxiao Shi71ff2312017-07-12 13:32:50 +0000315 component.toUri(os);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700316 }
Junxiao Shi71ff2312017-07-12 13:32:50 +0000317 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700318 return os;
319}
320
321std::istream&
322operator>>(std::istream& is, Name& name)
323{
324 std::string inputString;
325 is >> inputString;
Alexander Afanasyev66ca2032015-12-04 13:17:02 -0800326 name = Name(inputString);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700327
328 return is;
329}
330
331} // namespace ndn
Yingdi Yu90e23582014-11-06 14:21:04 -0800332
333namespace std {
Junxiao Shi71ff2312017-07-12 13:32:50 +0000334
Yingdi Yu90e23582014-11-06 14:21:04 -0800335size_t
336hash<ndn::Name>::operator()(const ndn::Name& name) const
337{
338 return boost::hash_range(name.wireEncode().wire(),
339 name.wireEncode().wire() + name.wireEncode().size());
340}
341
342} // namespace std