blob: 2e2dd6cfc929a3623ca27c045ecc9fc87672e182 [file] [log] [blame]
Alexander Afanasyev15f67312014-07-22 15:11:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shia6452ac2015-01-23 11:21:06 -07003 * Copyright (c) 2013-2015 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"
29#include "util/string-helper.hpp"
30#include "encoding/block.hpp"
31#include "encoding/encoding-buffer.hpp"
32
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)
58{
59 construct(uri);
60}
61
62Name::Name(const std::string& uri)
63{
64 construct(uri.c_str());
65}
66
Alexander Afanasyev74633892015-02-08 18:08:46 -080067template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -070068size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080069Name::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -070070{
71 size_t totalLength = 0;
72
73 for (const_reverse_iterator i = rbegin(); i != rend(); ++i)
74 {
75 totalLength += i->wireEncode(encoder);
76 }
77
78 totalLength += encoder.prependVarNumber(totalLength);
79 totalLength += encoder.prependVarNumber(tlv::Name);
80 return totalLength;
81}
82
83template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070084Name::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -070085
86template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080087Name::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -070088
89const Block&
90Name::wireEncode() const
91{
92 if (m_nameBlock.hasWire())
93 return m_nameBlock;
94
95 EncodingEstimator estimator;
96 size_t estimatedSize = wireEncode(estimator);
97
98 EncodingBuffer buffer(estimatedSize, 0);
99 wireEncode(buffer);
100
101 m_nameBlock = buffer.block();
102 m_nameBlock.parse();
103
104 return m_nameBlock;
105}
106
107void
108Name::wireDecode(const Block& wire)
109{
110 if (wire.type() != tlv::Name)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700111 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700112
113 m_nameBlock = wire;
114 m_nameBlock.parse();
115}
116
117void
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800118Name::construct(const char* uriOrig)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700119{
120 clear();
121
122 std::string uri = uriOrig;
123 trim(uri);
124 if (uri.size() == 0)
125 return;
126
127 size_t iColon = uri.find(':');
128 if (iColon != std::string::npos) {
129 // Make sure the colon came before a '/'.
130 size_t iFirstSlash = uri.find('/');
131 if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
132 // Omit the leading protocol such as ndn:
133 uri.erase(0, iColon + 1);
134 trim(uri);
135 }
136 }
137
138 // Trim the leading slash and possibly the authority.
139 if (uri[0] == '/') {
140 if (uri.size() >= 2 && uri[1] == '/') {
141 // Strip the authority following "//".
142 size_t iAfterAuthority = uri.find('/', 2);
143 if (iAfterAuthority == std::string::npos)
144 // Unusual case: there was only an authority.
145 return;
146 else {
147 uri.erase(0, iAfterAuthority + 1);
148 trim(uri);
149 }
150 }
151 else {
152 uri.erase(0, 1);
153 trim(uri);
154 }
155 }
156
157 size_t iComponentStart = 0;
158
159 // Unescape the components.
160 while (iComponentStart < uri.size()) {
161 size_t iComponentEnd = uri.find("/", iComponentStart);
162 if (iComponentEnd == std::string::npos)
163 iComponentEnd = uri.size();
164
Alexander Afanasyevd7eacc72015-04-03 13:06:26 -0700165 append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700166 iComponentStart = iComponentEnd + 1;
167 }
168}
169
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800170void
171Name::set(const char* uri)
172{
173 *this = std::move(Name(uri));
174}
175
176void
177Name::set(const std::string& uri)
178{
179 *this = std::move(Name(uri));
180}
181
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700182std::string
183Name::toUri() const
184{
185 std::ostringstream os;
186 os << *this;
187 return os.str();
188}
189
190Name&
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400191Name::append(const PartialName& name)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700192{
193 if (&name == this)
194 // Copying from this name, so need to make a copy first.
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400195 return append(PartialName(name));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700196
197 for (size_t i = 0; i < name.size(); ++i)
198 append(name.at(i));
199
200 return *this;
201}
202
203Name&
204Name::appendNumber(uint64_t number)
205{
206 m_nameBlock.push_back(Component::fromNumber(number));
207 return *this;
208}
209
210Name&
211Name::appendNumberWithMarker(uint8_t marker, uint64_t number)
212{
213 m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number));
214 return *this;
215}
216
217Name&
218Name::appendVersion(uint64_t version)
219{
220 m_nameBlock.push_back(Component::fromVersion(version));
221 return *this;
222}
223
224Name&
225Name::appendVersion()
226{
Junxiao Shi937e4612014-10-22 15:39:07 -0700227 appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700228 return *this;
229}
230
231Name&
232Name::appendSegment(uint64_t segmentNo)
233{
234 m_nameBlock.push_back(Component::fromSegment(segmentNo));
235 return *this;
236}
237
238Name&
239Name::appendSegmentOffset(uint64_t offset)
240{
241 m_nameBlock.push_back(Component::fromSegmentOffset(offset));
242 return *this;
243}
244
245Name&
246Name::appendTimestamp(const time::system_clock::TimePoint& timePoint)
247{
248 m_nameBlock.push_back(Component::fromTimestamp(timePoint));
249 return *this;
250}
251
252Name&
253Name::appendSequenceNumber(uint64_t seqNo)
254{
255 m_nameBlock.push_back(Component::fromSequenceNumber(seqNo));
256 return *this;
257}
258
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700259Name&
260Name::appendImplicitSha256Digest(const ConstBufferPtr& digest)
261{
262 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest));
263 return *this;
264}
265
266Name&
267Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
268{
269 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize));
270 return *this;
271}
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700272
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400273PartialName
274Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700275{
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400276 PartialName result;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700277
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400278 ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
Junxiao Shia6452ac2015-01-23 11:21:06 -0700279 size_t iEnd = this->size();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700280
Joao Pereira6f7cfd02015-06-15 11:36:26 -0400281 iStart = std::max(iStart, static_cast<ssize_t>(0));
282
283 if (nComponents != npos)
284 iEnd = std::min(this->size(), iStart + nComponents);
285
286 for (size_t i = iStart; i < iEnd; ++i)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700287 result.append(at(i));
288
289 return result;
290}
291
292Name
293Name::getSuccessor() const
294{
295 if (empty()) {
296 static uint8_t firstValue[] = { 0 };
297 Name firstName;
298 firstName.append(firstValue, 1);
299 return firstName;
300 }
301
302 return getPrefix(-1).append(get(-1).getSuccessor());
303}
304
305bool
306Name::equals(const Name& name) const
307{
308 if (size() != name.size())
309 return false;
310
311 for (size_t i = 0; i < size(); ++i) {
312 if (at(i) != name.at(i))
313 return false;
314 }
315
316 return true;
317}
318
319bool
320Name::isPrefixOf(const Name& name) const
321{
322 // This name is longer than the name we are checking against.
323 if (size() > name.size())
324 return false;
325
326 // Check if at least one of given components doesn't match.
327 for (size_t i = 0; i < size(); ++i) {
328 if (at(i) != name.at(i))
329 return false;
330 }
331
332 return true;
333}
334
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700335int
Junxiao Shia6452ac2015-01-23 11:21:06 -0700336Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700337{
Junxiao Shia6452ac2015-01-23 11:21:06 -0700338 count1 = std::min(count1, this->size() - pos1);
339 count2 = std::min(count2, other.size() - pos2);
340 size_t count = std::min(count1, count2);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700341
Junxiao Shia6452ac2015-01-23 11:21:06 -0700342 for (size_t i = 0; i < count; ++i) {
343 int comp = this->at(pos1 + i).compare(other.at(pos2 + i));
344 if (comp != 0) { // i-th component differs
345 return comp;
346 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700347 }
Junxiao Shia6452ac2015-01-23 11:21:06 -0700348 // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
Joao Pereiraaa8fd162015-06-05 16:35:15 -0400349 return count1 - count2;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700350}
351
352std::ostream&
353operator<<(std::ostream& os, const Name& name)
354{
355 if (name.empty())
356 {
357 os << "/";
358 }
359 else
360 {
361 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
362 os << "/";
363 i->toUri(os);
364 }
365 }
366 return os;
367}
368
369std::istream&
370operator>>(std::istream& is, Name& name)
371{
372 std::string inputString;
373 is >> inputString;
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800374 name = std::move(Name(inputString));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700375
376 return is;
377}
378
379} // namespace ndn
Yingdi Yu90e23582014-11-06 14:21:04 -0800380
381namespace std {
382size_t
383hash<ndn::Name>::operator()(const ndn::Name& name) const
384{
385 return boost::hash_range(name.wireEncode().wire(),
386 name.wireEncode().wire() + name.wireEncode().size());
387}
388
389} // namespace std