blob: ad15d08511f696658de2a930f640c02336cf16b1 [file] [log] [blame]
Alexander Afanasyev15f67312014-07-22 15:11:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
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
28#include "util/time.hpp"
Alexander Afanasyev15f67312014-07-22 15:11:09 -070029#include "encoding/block.hpp"
30#include "encoding/encoding-buffer.hpp"
31
Davide Pesaventodd461432017-01-28 21:47:26 -050032#include <boost/algorithm/string/trim.hpp>
Yingdi Yu90e23582014-11-06 14:21:04 -080033#include <boost/functional/hash.hpp>
34
Alexander Afanasyev15f67312014-07-22 15:11:09 -070035namespace ndn {
36
Junxiao Shic2b8d242014-11-04 08:35:29 -070037BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
38BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070039BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Name>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070040BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
41static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
42 "Name::Error must inherit from tlv::Error");
43
Junxiao Shia6452ac2015-01-23 11:21:06 -070044const size_t Name::npos = std::numeric_limits<size_t>::max();
45
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080046Name::Name()
47 : m_nameBlock(tlv::Name)
48{
49}
50
51Name::Name(const Block& wire)
52{
53 m_nameBlock = wire;
54 m_nameBlock.parse();
55}
56
57Name::Name(const char* uri)
Junxiao Shi3188c4032016-07-18 20:53:56 +000058 : Name(std::string(uri))
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080059{
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080060}
61
Junxiao Shi3188c4032016-07-18 20:53:56 +000062Name::Name(std::string uri)
Alexander Afanasyevc89efb42015-02-10 18:26:42 -080063{
Davide Pesaventodd461432017-01-28 21:47:26 -050064 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000065 if (uri.empty())
66 return;
67
68 size_t iColon = uri.find(':');
69 if (iColon != std::string::npos) {
70 // Make sure the colon came before a '/'.
71 size_t iFirstSlash = uri.find('/');
72 if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
73 // Omit the leading protocol such as ndn:
74 uri.erase(0, iColon + 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050075 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000076 }
77 }
78
79 // Trim the leading slash and possibly the authority.
80 if (uri[0] == '/') {
81 if (uri.size() >= 2 && uri[1] == '/') {
82 // Strip the authority following "//".
83 size_t iAfterAuthority = uri.find('/', 2);
84 if (iAfterAuthority == std::string::npos)
85 // Unusual case: there was only an authority.
86 return;
87 else {
88 uri.erase(0, iAfterAuthority + 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050089 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000090 }
91 }
92 else {
93 uri.erase(0, 1);
Davide Pesaventodd461432017-01-28 21:47:26 -050094 boost::algorithm::trim(uri);
Junxiao Shi3188c4032016-07-18 20:53:56 +000095 }
96 }
97
98 size_t iComponentStart = 0;
99
100 // Unescape the components.
101 while (iComponentStart < uri.size()) {
102 size_t iComponentEnd = uri.find("/", iComponentStart);
103 if (iComponentEnd == std::string::npos)
104 iComponentEnd = uri.size();
105
106 append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
107 iComponentStart = iComponentEnd + 1;
108 }
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800109}
110
Alexander Afanasyev4f512fb2016-05-18 10:47:53 -0700111Name
112Name::deepCopy() const
113{
114 Name copiedName(*this);
115 copiedName.m_nameBlock.resetWire();
116 copiedName.wireEncode(); // "compress" the underlying buffer
117 return copiedName;
118}
119
Alexander Afanasyev74633892015-02-08 18:08:46 -0800120template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700121size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800122Name::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700123{
124 size_t totalLength = 0;
125
126 for (const_reverse_iterator i = rbegin(); i != rend(); ++i)
127 {
128 totalLength += i->wireEncode(encoder);
129 }
130
131 totalLength += encoder.prependVarNumber(totalLength);
132 totalLength += encoder.prependVarNumber(tlv::Name);
133 return totalLength;
134}
135
136template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700137Name::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700138
139template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800140Name::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700141
142const Block&
143Name::wireEncode() const
144{
145 if (m_nameBlock.hasWire())
146 return m_nameBlock;
147
148 EncodingEstimator estimator;
149 size_t estimatedSize = wireEncode(estimator);
150
151 EncodingBuffer buffer(estimatedSize, 0);
152 wireEncode(buffer);
153
154 m_nameBlock = buffer.block();
155 m_nameBlock.parse();
156
157 return m_nameBlock;
158}
159
160void
161Name::wireDecode(const Block& wire)
162{
163 if (wire.type() != tlv::Name)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700164 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700165
166 m_nameBlock = wire;
167 m_nameBlock.parse();
168}
169
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700170std::string
171Name::toUri() const
172{
173 std::ostringstream os;
174 os << *this;
175 return os.str();
176}
177
178Name&
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400179Name::append(const PartialName& name)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700180{
181 if (&name == this)
182 // Copying from this name, so need to make a copy first.
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400183 return append(PartialName(name));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700184
185 for (size_t i = 0; i < name.size(); ++i)
186 append(name.at(i));
187
188 return *this;
189}
190
191Name&
192Name::appendNumber(uint64_t number)
193{
194 m_nameBlock.push_back(Component::fromNumber(number));
195 return *this;
196}
197
198Name&
199Name::appendNumberWithMarker(uint8_t marker, uint64_t number)
200{
201 m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number));
202 return *this;
203}
204
205Name&
206Name::appendVersion(uint64_t version)
207{
208 m_nameBlock.push_back(Component::fromVersion(version));
209 return *this;
210}
211
212Name&
213Name::appendVersion()
214{
Junxiao Shi937e4612014-10-22 15:39:07 -0700215 appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700216 return *this;
217}
218
219Name&
220Name::appendSegment(uint64_t segmentNo)
221{
222 m_nameBlock.push_back(Component::fromSegment(segmentNo));
223 return *this;
224}
225
226Name&
227Name::appendSegmentOffset(uint64_t offset)
228{
229 m_nameBlock.push_back(Component::fromSegmentOffset(offset));
230 return *this;
231}
232
233Name&
234Name::appendTimestamp(const time::system_clock::TimePoint& timePoint)
235{
236 m_nameBlock.push_back(Component::fromTimestamp(timePoint));
237 return *this;
238}
239
240Name&
241Name::appendSequenceNumber(uint64_t seqNo)
242{
243 m_nameBlock.push_back(Component::fromSequenceNumber(seqNo));
244 return *this;
245}
246
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700247Name&
248Name::appendImplicitSha256Digest(const ConstBufferPtr& digest)
249{
250 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest));
251 return *this;
252}
253
254Name&
255Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
256{
257 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize));
258 return *this;
259}
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700260
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400261PartialName
262Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700263{
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400264 PartialName result;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700265
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400266 ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
Junxiao Shia6452ac2015-01-23 11:21:06 -0700267 size_t iEnd = this->size();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700268
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400269 iStart = std::max(iStart, static_cast<ssize_t>(0));
270
271 if (nComponents != npos)
272 iEnd = std::min(this->size(), iStart + nComponents);
273
274 for (size_t i = iStart; i < iEnd; ++i)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700275 result.append(at(i));
276
277 return result;
278}
279
280Name
281Name::getSuccessor() const
282{
283 if (empty()) {
284 static uint8_t firstValue[] = { 0 };
285 Name firstName;
286 firstName.append(firstValue, 1);
287 return firstName;
288 }
289
290 return getPrefix(-1).append(get(-1).getSuccessor());
291}
292
293bool
294Name::equals(const Name& name) const
295{
296 if (size() != name.size())
297 return false;
298
299 for (size_t i = 0; i < size(); ++i) {
300 if (at(i) != name.at(i))
301 return false;
302 }
303
304 return true;
305}
306
307bool
308Name::isPrefixOf(const Name& name) const
309{
310 // This name is longer than the name we are checking against.
311 if (size() > name.size())
312 return false;
313
314 // Check if at least one of given components doesn't match.
315 for (size_t i = 0; i < size(); ++i) {
316 if (at(i) != name.at(i))
317 return false;
318 }
319
320 return true;
321}
322
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700323int
Junxiao Shia6452ac2015-01-23 11:21:06 -0700324Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700325{
Junxiao Shia6452ac2015-01-23 11:21:06 -0700326 count1 = std::min(count1, this->size() - pos1);
327 count2 = std::min(count2, other.size() - pos2);
328 size_t count = std::min(count1, count2);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700329
Junxiao Shia6452ac2015-01-23 11:21:06 -0700330 for (size_t i = 0; i < count; ++i) {
331 int comp = this->at(pos1 + i).compare(other.at(pos2 + i));
332 if (comp != 0) { // i-th component differs
333 return comp;
334 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700335 }
Junxiao Shia6452ac2015-01-23 11:21:06 -0700336 // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
Joao Pereiraaa8fd162015-06-05 16:35:15 -0400337 return count1 - count2;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700338}
339
340std::ostream&
341operator<<(std::ostream& os, const Name& name)
342{
343 if (name.empty())
344 {
345 os << "/";
346 }
347 else
348 {
349 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
350 os << "/";
351 i->toUri(os);
352 }
353 }
354 return os;
355}
356
357std::istream&
358operator>>(std::istream& is, Name& name)
359{
360 std::string inputString;
361 is >> inputString;
Alexander Afanasyev66ca2032015-12-04 13:17:02 -0800362 name = Name(inputString);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700363
364 return is;
365}
366
367} // namespace ndn
Yingdi Yu90e23582014-11-06 14:21:04 -0800368
369namespace std {
370size_t
371hash<ndn::Name>::operator()(const ndn::Name& name) const
372{
373 return boost::hash_range(name.wireEncode().wire(),
374 name.wireEncode().wire() + name.wireEncode().size());
375}
376
377} // namespace std