blob: b180ba60eeb354afa26f93f8fa8454793aa26ecb [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
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&
191Name::append(const Name& name)
192{
193 if (&name == this)
194 // Copying from this name, so need to make a copy first.
195 return append(Name(name));
196
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
273Name
274Name::getSubName(size_t iStartComponent, size_t nComponents) const
275{
276 Name result;
277
Junxiao Shia6452ac2015-01-23 11:21:06 -0700278 size_t iEnd = this->size();
279 if (nComponents != npos)
280 iEnd = std::min(this->size(), iStartComponent + nComponents);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700281
Junxiao Shia6452ac2015-01-23 11:21:06 -0700282 for (size_t i = iStartComponent; i < iEnd; ++i)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700283 result.append(at(i));
284
285 return result;
286}
287
288Name
289Name::getSuccessor() const
290{
291 if (empty()) {
292 static uint8_t firstValue[] = { 0 };
293 Name firstName;
294 firstName.append(firstValue, 1);
295 return firstName;
296 }
297
298 return getPrefix(-1).append(get(-1).getSuccessor());
299}
300
301bool
302Name::equals(const Name& name) const
303{
304 if (size() != name.size())
305 return false;
306
307 for (size_t i = 0; i < size(); ++i) {
308 if (at(i) != name.at(i))
309 return false;
310 }
311
312 return true;
313}
314
315bool
316Name::isPrefixOf(const Name& name) const
317{
318 // This name is longer than the name we are checking against.
319 if (size() > name.size())
320 return false;
321
322 // Check if at least one of given components doesn't match.
323 for (size_t i = 0; i < size(); ++i) {
324 if (at(i) != name.at(i))
325 return false;
326 }
327
328 return true;
329}
330
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700331int
Junxiao Shia6452ac2015-01-23 11:21:06 -0700332Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700333{
Junxiao Shia6452ac2015-01-23 11:21:06 -0700334 count1 = std::min(count1, this->size() - pos1);
335 count2 = std::min(count2, other.size() - pos2);
336 size_t count = std::min(count1, count2);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700337
Junxiao Shia6452ac2015-01-23 11:21:06 -0700338 for (size_t i = 0; i < count; ++i) {
339 int comp = this->at(pos1 + i).compare(other.at(pos2 + i));
340 if (comp != 0) { // i-th component differs
341 return comp;
342 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700343 }
Junxiao Shia6452ac2015-01-23 11:21:06 -0700344 // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
345 return (count1 > count2) - (count1 < count2); // signum(count1 - count2)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700346}
347
348std::ostream&
349operator<<(std::ostream& os, const Name& name)
350{
351 if (name.empty())
352 {
353 os << "/";
354 }
355 else
356 {
357 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
358 os << "/";
359 i->toUri(os);
360 }
361 }
362 return os;
363}
364
365std::istream&
366operator>>(std::istream& is, Name& name)
367{
368 std::string inputString;
369 is >> inputString;
Alexander Afanasyevc89efb42015-02-10 18:26:42 -0800370 name = std::move(Name(inputString));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700371
372 return is;
373}
374
375} // namespace ndn
Yingdi Yu90e23582014-11-06 14:21:04 -0800376
377namespace std {
378size_t
379hash<ndn::Name>::operator()(const ndn::Name& name) const
380{
381 return boost::hash_range(name.wireEncode().wire(),
382 name.wireEncode().wire() + name.wireEncode().size());
383}
384
385} // namespace std