blob: c38806418aa7861b6a3875544aed2a6c78bc5318 [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"
Junxiao Shic2b8d242014-11-04 08:35:29 -070030#include "util/concepts.hpp"
Alexander Afanasyev15f67312014-07-22 15:11:09 -070031#include "encoding/block.hpp"
32#include "encoding/encoding-buffer.hpp"
33
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>));
40BOOST_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 Afanasyev74633892015-02-08 18:08:46 -080084Name::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& estimator) 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)
111 throw tlv::Error("Unexpected TLV type when decoding Name");
112
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
165 Component component = Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd);
166 // Ignore illegal components. This also gets rid of a trailing '/'.
167 if (!component.empty())
168 append(Component(component));
169
170 iComponentStart = iComponentEnd + 1;
171 }
172}
173
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800174void
175Name::set(const char* uri)
176{
177 *this = std::move(Name(uri));
178}
179
180void
181Name::set(const std::string& uri)
182{
183 *this = std::move(Name(uri));
184}
185
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700186std::string
187Name::toUri() const
188{
189 std::ostringstream os;
190 os << *this;
191 return os.str();
192}
193
194Name&
195Name::append(const Name& name)
196{
197 if (&name == this)
198 // Copying from this name, so need to make a copy first.
199 return append(Name(name));
200
201 for (size_t i = 0; i < name.size(); ++i)
202 append(name.at(i));
203
204 return *this;
205}
206
207Name&
208Name::appendNumber(uint64_t number)
209{
210 m_nameBlock.push_back(Component::fromNumber(number));
211 return *this;
212}
213
214Name&
215Name::appendNumberWithMarker(uint8_t marker, uint64_t number)
216{
217 m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number));
218 return *this;
219}
220
221Name&
222Name::appendVersion(uint64_t version)
223{
224 m_nameBlock.push_back(Component::fromVersion(version));
225 return *this;
226}
227
228Name&
229Name::appendVersion()
230{
Junxiao Shi937e4612014-10-22 15:39:07 -0700231 appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700232 return *this;
233}
234
235Name&
236Name::appendSegment(uint64_t segmentNo)
237{
238 m_nameBlock.push_back(Component::fromSegment(segmentNo));
239 return *this;
240}
241
242Name&
243Name::appendSegmentOffset(uint64_t offset)
244{
245 m_nameBlock.push_back(Component::fromSegmentOffset(offset));
246 return *this;
247}
248
249Name&
250Name::appendTimestamp(const time::system_clock::TimePoint& timePoint)
251{
252 m_nameBlock.push_back(Component::fromTimestamp(timePoint));
253 return *this;
254}
255
256Name&
257Name::appendSequenceNumber(uint64_t seqNo)
258{
259 m_nameBlock.push_back(Component::fromSequenceNumber(seqNo));
260 return *this;
261}
262
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700263Name&
264Name::appendImplicitSha256Digest(const ConstBufferPtr& digest)
265{
266 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest));
267 return *this;
268}
269
270Name&
271Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
272{
273 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize));
274 return *this;
275}
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700276
277Name
278Name::getSubName(size_t iStartComponent, size_t nComponents) const
279{
280 Name result;
281
Junxiao Shia6452ac2015-01-23 11:21:06 -0700282 size_t iEnd = this->size();
283 if (nComponents != npos)
284 iEnd = std::min(this->size(), iStartComponent + nComponents);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700285
Junxiao Shia6452ac2015-01-23 11:21:06 -0700286 for (size_t i = iStartComponent; 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
349 return (count1 > count2) - (count1 < count2); // signum(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