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