blob: f9d91db2c42570ca1a2ba4f8d00f27382ec8e670 [file] [log] [blame]
Alexander Afanasyev15f67312014-07-22 15:11:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2014 Regents of the University of California.
4 *
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
Alexander Afanasyev15f67312014-07-22 15:11:09 -070044template<bool T>
45size_t
46Name::wireEncode(EncodingImpl<T>& encoder) const
47{
48 size_t totalLength = 0;
49
50 for (const_reverse_iterator i = rbegin(); i != rend(); ++i)
51 {
52 totalLength += i->wireEncode(encoder);
53 }
54
55 totalLength += encoder.prependVarNumber(totalLength);
56 totalLength += encoder.prependVarNumber(tlv::Name);
57 return totalLength;
58}
59
60template size_t
61Name::wireEncode<true>(EncodingImpl<true>& estimator) const;
62
63template size_t
64Name::wireEncode<false>(EncodingImpl<false>& encoder) const;
65
66const Block&
67Name::wireEncode() const
68{
69 if (m_nameBlock.hasWire())
70 return m_nameBlock;
71
72 EncodingEstimator estimator;
73 size_t estimatedSize = wireEncode(estimator);
74
75 EncodingBuffer buffer(estimatedSize, 0);
76 wireEncode(buffer);
77
78 m_nameBlock = buffer.block();
79 m_nameBlock.parse();
80
81 return m_nameBlock;
82}
83
84void
85Name::wireDecode(const Block& wire)
86{
87 if (wire.type() != tlv::Name)
88 throw tlv::Error("Unexpected TLV type when decoding Name");
89
90 m_nameBlock = wire;
91 m_nameBlock.parse();
92}
93
94void
95Name::set(const char* uriOrig)
96{
97 clear();
98
99 std::string uri = uriOrig;
100 trim(uri);
101 if (uri.size() == 0)
102 return;
103
104 size_t iColon = uri.find(':');
105 if (iColon != std::string::npos) {
106 // Make sure the colon came before a '/'.
107 size_t iFirstSlash = uri.find('/');
108 if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
109 // Omit the leading protocol such as ndn:
110 uri.erase(0, iColon + 1);
111 trim(uri);
112 }
113 }
114
115 // Trim the leading slash and possibly the authority.
116 if (uri[0] == '/') {
117 if (uri.size() >= 2 && uri[1] == '/') {
118 // Strip the authority following "//".
119 size_t iAfterAuthority = uri.find('/', 2);
120 if (iAfterAuthority == std::string::npos)
121 // Unusual case: there was only an authority.
122 return;
123 else {
124 uri.erase(0, iAfterAuthority + 1);
125 trim(uri);
126 }
127 }
128 else {
129 uri.erase(0, 1);
130 trim(uri);
131 }
132 }
133
134 size_t iComponentStart = 0;
135
136 // Unescape the components.
137 while (iComponentStart < uri.size()) {
138 size_t iComponentEnd = uri.find("/", iComponentStart);
139 if (iComponentEnd == std::string::npos)
140 iComponentEnd = uri.size();
141
142 Component component = Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd);
143 // Ignore illegal components. This also gets rid of a trailing '/'.
144 if (!component.empty())
145 append(Component(component));
146
147 iComponentStart = iComponentEnd + 1;
148 }
149}
150
151std::string
152Name::toUri() const
153{
154 std::ostringstream os;
155 os << *this;
156 return os.str();
157}
158
159Name&
160Name::append(const Name& name)
161{
162 if (&name == this)
163 // Copying from this name, so need to make a copy first.
164 return append(Name(name));
165
166 for (size_t i = 0; i < name.size(); ++i)
167 append(name.at(i));
168
169 return *this;
170}
171
172Name&
173Name::appendNumber(uint64_t number)
174{
175 m_nameBlock.push_back(Component::fromNumber(number));
176 return *this;
177}
178
179Name&
180Name::appendNumberWithMarker(uint8_t marker, uint64_t number)
181{
182 m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number));
183 return *this;
184}
185
186Name&
187Name::appendVersion(uint64_t version)
188{
189 m_nameBlock.push_back(Component::fromVersion(version));
190 return *this;
191}
192
193Name&
194Name::appendVersion()
195{
Junxiao Shi937e4612014-10-22 15:39:07 -0700196 appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700197 return *this;
198}
199
200Name&
201Name::appendSegment(uint64_t segmentNo)
202{
203 m_nameBlock.push_back(Component::fromSegment(segmentNo));
204 return *this;
205}
206
207Name&
208Name::appendSegmentOffset(uint64_t offset)
209{
210 m_nameBlock.push_back(Component::fromSegmentOffset(offset));
211 return *this;
212}
213
214Name&
215Name::appendTimestamp(const time::system_clock::TimePoint& timePoint)
216{
217 m_nameBlock.push_back(Component::fromTimestamp(timePoint));
218 return *this;
219}
220
221Name&
222Name::appendSequenceNumber(uint64_t seqNo)
223{
224 m_nameBlock.push_back(Component::fromSequenceNumber(seqNo));
225 return *this;
226}
227
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700228Name&
229Name::appendImplicitSha256Digest(const ConstBufferPtr& digest)
230{
231 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest));
232 return *this;
233}
234
235Name&
236Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
237{
238 m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize));
239 return *this;
240}
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700241
242Name
243Name::getSubName(size_t iStartComponent, size_t nComponents) const
244{
245 Name result;
246
247 size_t iEnd = iStartComponent + nComponents;
248 for (size_t i = iStartComponent; i < iEnd && i < size(); ++i)
249 result.append(at(i));
250
251 return result;
252}
253
254Name
255Name::getSubName(size_t iStartComponent) const
256{
257 Name result;
258
259 for (size_t i = iStartComponent; i < size(); ++i)
260 result.append(at(i));
261
262 return result;
263}
264
265Name
266Name::getSuccessor() const
267{
268 if (empty()) {
269 static uint8_t firstValue[] = { 0 };
270 Name firstName;
271 firstName.append(firstValue, 1);
272 return firstName;
273 }
274
275 return getPrefix(-1).append(get(-1).getSuccessor());
276}
277
278bool
279Name::equals(const Name& name) const
280{
281 if (size() != name.size())
282 return false;
283
284 for (size_t i = 0; i < size(); ++i) {
285 if (at(i) != name.at(i))
286 return false;
287 }
288
289 return true;
290}
291
292bool
293Name::isPrefixOf(const Name& name) const
294{
295 // This name is longer than the name we are checking against.
296 if (size() > name.size())
297 return false;
298
299 // Check if at least one of given components doesn't match.
300 for (size_t i = 0; i < size(); ++i) {
301 if (at(i) != name.at(i))
302 return false;
303 }
304
305 return true;
306}
307
308
309int
310Name::compare(const Name& other) const
311{
312 for (size_t i = 0; i < size() && i < other.size(); ++i) {
313 int comparison = at(i).compare(other.at(i));
314 if (comparison == 0)
315 // The components at this index are equal, so check the next components.
316 continue;
317
318 // Otherwise, the result is based on the components at this index.
319 return comparison;
320 }
321
322 // The components up to min(this.size(), other.size()) are equal, so the shorter name is less.
323 if (size() < other.size())
324 return -1;
325 else if (size() > other.size())
326 return 1;
327 else
328 return 0;
329}
330
331std::ostream&
332operator<<(std::ostream& os, const Name& name)
333{
334 if (name.empty())
335 {
336 os << "/";
337 }
338 else
339 {
340 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
341 os << "/";
342 i->toUri(os);
343 }
344 }
345 return os;
346}
347
348std::istream&
349operator>>(std::istream& is, Name& name)
350{
351 std::string inputString;
352 is >> inputString;
353 name.set(inputString);
354
355 return is;
356}
357
358} // namespace ndn
Yingdi Yu90e23582014-11-06 14:21:04 -0800359
360namespace std {
361size_t
362hash<ndn::Name>::operator()(const ndn::Name& name) const
363{
364 return boost::hash_range(name.wireEncode().wire(),
365 name.wireEncode().wire() + name.wireEncode().size());
366}
367
368} // namespace std