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