blob: 7a3d17133ee009e41424b9681a8e5e187f4c34ef [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompson47eecfc2013-07-07 22:56:46 -07002/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07003 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompsona98000c2013-12-16 14:40:09 -08005 * @author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
Jeff Thompson47eecfc2013-07-07 22:56:46 -07006 * See COPYING for copyright and distribution information.
Jeff Thompson9c41dfe2013-06-27 12:10:25 -07007 */
8
Jeff Thompson54909772013-07-07 22:38:57 -07009#include <stdexcept>
Jeff Thompsonb8f1b132013-08-13 11:07:43 -070010#include <algorithm>
Jeff Thompsond8e53e62013-10-29 16:59:49 -070011#include <string.h>
Yingdi Yu61ec2722014-01-20 14:22:32 -080012#include <ndn-cpp-dev/name.hpp>
Jeff Thompsona98000c2013-12-16 14:40:09 -080013#include "c/util/ndn_memory.h"
Alexander Afanasyev594cdb22014-01-03 15:11:33 -080014#include "c/util/time.h"
Jeff Thompson9c41dfe2013-06-27 12:10:25 -070015
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080016#include "util/string-helper.hpp"
17
Jeff Thompson9c41dfe2013-06-27 12:10:25 -070018using namespace std;
19
20namespace ndn {
21
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080022uint64_t
23Name::Component::toNumberWithMarker(uint8_t marker) const
Jeff Thompson26c63d62013-07-02 18:00:26 -070024{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080025 if (empty() || *getValue().begin() != marker)
26 throw runtime_error("Name component does not begin with the expected marker");
Jeff Thompson26c63d62013-07-02 18:00:26 -070027
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080028 uint64_t result = 0;
29 for (Buffer::const_iterator i = getValue().begin()+1; i != getValue().end(); ++i) {
30 result <<= 8;
31 result |= *i;
Jeff Thompson26c63d62013-07-02 18:00:26 -070032 }
33
Jeff Thompson27cae532013-10-08 12:52:41 -070034 return result;
35}
36
Jeff Thompsond129ac12013-10-11 14:30:12 -070037Name::Component
Jeff Thompsond129ac12013-10-11 14:30:12 -070038Name::Component::fromNumber(uint64_t number)
Jeff Thompson8aac1992013-08-12 17:26:02 -070039{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080040 ptr_lib::shared_ptr<Buffer> value(new Buffer);
Jeff Thompson8aac1992013-08-12 17:26:02 -070041
Jeff Thompsond129ac12013-10-11 14:30:12 -070042 // First encode in little endian.
43 while (number != 0) {
44 value->push_back(number & 0xff);
45 number >>= 8;
46 }
47
48 // Make it big endian.
49 reverse(value->begin(), value->end());
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080050 return Component(value);
Jeff Thompsond129ac12013-10-11 14:30:12 -070051}
52
Alexander Afanasyev848c61a2014-01-03 13:52:04 -080053Name::Component
Jeff Thompsond129ac12013-10-11 14:30:12 -070054Name::Component::fromNumberWithMarker(uint64_t number, uint8_t marker)
55{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080056 ptr_lib::shared_ptr<Buffer> value(new Buffer);
Jeff Thompsond129ac12013-10-11 14:30:12 -070057
58 // Add the leading marker.
59 value->push_back(marker);
Jeff Thompsonb8f1b132013-08-13 11:07:43 -070060
Jeff Thompson8aac1992013-08-12 17:26:02 -070061 // First encode in little endian.
Jeff Thompsond129ac12013-10-11 14:30:12 -070062 while (number != 0) {
63 value->push_back(number & 0xff);
64 number >>= 8;
Jeff Thompson8aac1992013-08-12 17:26:02 -070065 }
66
Jeff Thompson8aac1992013-08-12 17:26:02 -070067 // Make it big endian.
Jeff Thompson995aba52013-09-12 12:04:52 -070068 reverse(value->begin() + 1, value->end());
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080069 return Component(value);
Jeff Thompson25b4e612013-10-10 16:03:24 -070070}
71
72uint64_t
73Name::Component::toNumber() const
74{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080075 uint64_t result = 0;
76 for (Buffer::const_iterator i = getValue().begin(); i != getValue().end(); ++i) {
77 result <<= 8;
78 result |= *i;
79 }
80
81 return result;
Jeff Thompson25b4e612013-10-10 16:03:24 -070082}
83
Jeff Thompsona98000c2013-12-16 14:40:09 -080084int
85Name::Component::compare(const Name::Component& other) const
86{
87 // Imitate ndn_Exclude_compareComponents.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080088 if (getValue().size() < other.getValue().size())
Jeff Thompsona98000c2013-12-16 14:40:09 -080089 return -1;
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080090 if (getValue().size() > other.getValue().size())
Jeff Thompsona98000c2013-12-16 14:40:09 -080091 return 1;
92
93 // The components are equal length. Just do a byte compare.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080094 return ndn_memcmp(getValue().buf(), other.getValue().buf(), getValue().size());
Jeff Thompsona98000c2013-12-16 14:40:09 -080095}
96
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080097// const Block &
98// Name::wireEncode() const
99// {
100
101// }
102
Jeff Thompson25b4e612013-10-10 16:03:24 -0700103void
Jeff Thompson0050abe2013-09-17 12:50:25 -0700104Name::set(const char *uri_cstr)
Jeff Thompson443398d2013-07-02 19:45:46 -0700105{
Jeff Thompson67515bd2013-08-15 17:43:22 -0700106 components_.clear();
107
Jeff Thompson443398d2013-07-02 19:45:46 -0700108 string uri = uri_cstr;
109 trim(uri);
110 if (uri.size() == 0)
111 return;
112
113 size_t iColon = uri.find(':');
114 if (iColon != string::npos) {
115 // Make sure the colon came before a '/'.
116 size_t iFirstSlash = uri.find('/');
117 if (iFirstSlash == string::npos || iColon < iFirstSlash) {
118 // Omit the leading protocol such as ndn:
119 uri.erase(0, iColon + 1);
120 trim(uri);
121 }
122 }
123
124 // Trim the leading slash and possibly the authority.
125 if (uri[0] == '/') {
126 if (uri.size() >= 2 && uri[1] == '/') {
127 // Strip the authority following "//".
128 size_t iAfterAuthority = uri.find('/', 2);
129 if (iAfterAuthority == string::npos)
130 // Unusual case: there was only an authority.
131 return;
132 else {
133 uri.erase(0, iAfterAuthority + 1);
134 trim(uri);
135 }
136 }
137 else {
138 uri.erase(0, 1);
139 trim(uri);
140 }
141 }
142
143 size_t iComponentStart = 0;
144
145 // Unescape the components.
146 while (iComponentStart < uri.size()) {
147 size_t iComponentEnd = uri.find("/", iComponentStart);
148 if (iComponentEnd == string::npos)
149 iComponentEnd = uri.size();
150
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700151 Component component(fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
Jeff Thompson46411c92013-09-13 19:31:25 -0700152 // Ignore illegal components. This also gets rid of a trailing '/'.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800153 if (!component.empty())
Jeff Thompson46411c92013-09-13 19:31:25 -0700154 components_.push_back(Component(component));
Jeff Thompson443398d2013-07-02 19:45:46 -0700155
156 iComponentStart = iComponentEnd + 1;
157 }
158}
159
Jeff Thompson26b0d792013-09-23 16:19:01 -0700160Name&
161Name::append(const Name& name)
162{
163 if (&name == this)
164 // Copying from this name, so need to make a copy first.
165 return append(Name(name));
166
167 for (size_t i = 0; i < name.components_.size(); ++i)
168 components_.push_back(name.components_[i]);
169
170 return *this;
171}
172
Alexander Afanasyev594cdb22014-01-03 15:11:33 -0800173Name&
174Name::appendVersion()
175{
176 appendVersion(ndn_getNowMilliseconds());
177 return *this;
178}
179
Jeff Thompsond0159d72013-09-23 13:34:15 -0700180Name
181Name::getSubName(size_t iStartComponent, size_t nComponents) const
182{
183 Name result;
184
Jeff Thompson97223af2013-09-24 17:01:27 -0700185 size_t iEnd = iStartComponent + nComponents;
186 for (size_t i = iStartComponent; i < iEnd && i < components_.size(); ++i)
Jeff Thompsond0159d72013-09-23 13:34:15 -0700187 result.components_.push_back(components_[i]);
188
189 return result;
190}
191
192Name
193Name::getSubName(size_t iStartComponent) const
194{
195 Name result;
196
Jeff Thompson97223af2013-09-24 17:01:27 -0700197 for (size_t i = iStartComponent; i < components_.size(); ++i)
Jeff Thompsond0159d72013-09-23 13:34:15 -0700198 result.components_.push_back(components_[i]);
199
200 return result;
201}
202
Jeff Thompson0050abe2013-09-17 12:50:25 -0700203bool
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700204Name::equals(const Name& name) const
205{
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700206 if (components_.size() != name.components_.size())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700207 return false;
208
209 for (size_t i = 0; i < components_.size(); ++i) {
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800210 if (components_[i].getValue() != name.components_[i].getValue())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700211 return false;
212 }
213
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700214 return true;
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700215}
216
217bool
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800218Name::isPrefixOf(const Name& name) const
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700219{
220 // Imitate ndn_Name_match.
221
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700222 // This name is longer than the name we are checking it against.
223 if (components_.size() > name.components_.size())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700224 return false;
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700225
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700226 // Check if at least one of given components doesn't match.
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700227 for (size_t i = 0; i < components_.size(); ++i) {
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800228 if (components_[i].getValue() != name.components_[i].getValue())
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700229 return false;
230 }
231
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700232 return true;
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700233}
234
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800235Name::Component
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700236Name::fromEscapedString(const char *escapedString, size_t beginOffset, size_t endOffset)
237{
238 string trimmedString(escapedString + beginOffset, escapedString + endOffset);
239 trim(trimmedString);
240 string value = unescape(trimmedString);
241
242 if (value.find_first_not_of(".") == string::npos) {
243 // Special case for component of only periods.
244 if (value.size() <= 2)
245 // Zero, one or two periods is illegal. Ignore this component.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800246 return Component();
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700247 else
248 // Remove 3 periods.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800249 return Component((const uint8_t *)&value[3], value.size() - 3);
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700250 }
251 else
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800252 return Component((const uint8_t *)&value[0], value.size());
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700253}
254
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800255Name::Component
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700256Name::fromEscapedString(const char *escapedString)
257{
258 return fromEscapedString(escapedString, 0, ::strlen(escapedString));
259}
260
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800261void
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800262Name::toEscapedString(const uint8_t *value, size_t valueSize, std::ostream& result)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700263{
264 bool gotNonDot = false;
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800265 for (unsigned i = 0; i < valueSize; ++i) {
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700266 if (value[i] != 0x2e) {
267 gotNonDot = true;
268 break;
269 }
270 }
271 if (!gotNonDot) {
272 // Special case for component of zero or more periods. Add 3 periods.
273 result << "...";
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800274 for (size_t i = 0; i < valueSize; ++i)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700275 result << '.';
276 }
277 else {
278 // In case we need to escape, set to upper case hex and save the previous flags.
279 ios::fmtflags saveFlags = result.flags(ios::hex | ios::uppercase);
280
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800281 for (size_t i = 0; i < valueSize; ++i) {
Jeff Thompson10ad12a2013-09-24 16:19:11 -0700282 uint8_t x = value[i];
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700283 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
Jeff Thompsonf68a74a2013-11-20 15:16:11 -0800284 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
285 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
286 x == 0x2e || x == 0x5f)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700287 result << x;
288 else {
289 result << '%';
290 if (x < 16)
291 result << '0';
292 result << (unsigned int)x;
293 }
294 }
295
296 // Restore.
297 result.flags(saveFlags);
298 }
299}
300
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800301int
302Name::compare(const Name& other) const
Jeff Thompson82568ad2013-12-17 15:17:40 -0800303{
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800304 for (size_t i = 0; i < size() && i < other.size(); ++i) {
305 int comparison = components_[i].compare(other.components_[i]);
306 if (comparison == 0)
Jeff Thompson82568ad2013-12-17 15:17:40 -0800307 // The components at this index are equal, so check the next components.
308 continue;
309
310 // Otherwise, the result is based on the components at this index.
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800311 return comparison;
Jeff Thompson82568ad2013-12-17 15:17:40 -0800312 }
313
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800314 // The components up to min(this.size(), other.size()) are equal, so the shorter name is less.
315 if (size() < other.size())
316 return -1;
317 else if (size() > other.size())
318 return 1;
319 else
320 return 0;
Jeff Thompson82568ad2013-12-17 15:17:40 -0800321}
322
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800323std::ostream&
324operator << (std::ostream& os, const Name& name)
325{
326 if (name.empty())
327 {
328 os << "/";
329 }
330 else
331 {
332 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
333 os << "/";
334 i->toEscapedString(os);
335 }
336 }
337
338 return os;
339}
Jeff Thompson82568ad2013-12-17 15:17:40 -0800340
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800341const Block &
342Name::wireEncode() const
343{
344 if (wire_.hasWire())
345 return wire_;
346
347 wire_ = Block(Tlv::Name);
348 for (Name::const_iterator i = begin(); i != end(); i++) {
349 OBufferStream os;
350 Tlv::writeVarNumber(os, Tlv::NameComponent);
351 Tlv::writeVarNumber(os, i->getValue().size());
352 os.write(reinterpret_cast<const char*>(i->getValue().buf()), i->getValue().size());
353
354 wire_.push_back(Block(os.buf()));
355 }
356
357 wire_.encode();
358 return wire_;
359}
360
361void
362Name::wireDecode(const Block &wire)
363{
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800364 clear();
365
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800366 wire_ = wire;
367 wire_.parse();
368
Alexander Afanasyev7b4a7fc2014-01-10 10:11:07 -0800369 components_.clear();
370 components_.reserve(wire_.getAll().size());
371
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800372 for (Block::element_const_iterator i = wire_.getAll().begin();
373 i != wire_.getAll().end();
374 ++i)
375 {
376 append(i->value(), i->value_size());
377 }
378}
Jeff Thompson9c41dfe2013-06-27 12:10:25 -0700379}