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