blob: 3e2d1feb55dc562043115aaf17703c86fa7d704a [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>
Alexander Afanasyevd409d592014-01-28 18:36:38 -080013#include "util/time.hpp"
Jeff Thompson9c41dfe2013-06-27 12:10:25 -070014
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080015#include "util/string-helper.hpp"
16
Jeff Thompson9c41dfe2013-06-27 12:10:25 -070017using namespace std;
18
19namespace ndn {
20
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080021uint64_t
22Name::Component::toNumberWithMarker(uint8_t marker) const
Jeff Thompson26c63d62013-07-02 18:00:26 -070023{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080024 if (empty() || *getValue().begin() != marker)
25 throw runtime_error("Name component does not begin with the expected marker");
Jeff Thompson26c63d62013-07-02 18:00:26 -070026
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080027 uint64_t result = 0;
28 for (Buffer::const_iterator i = getValue().begin()+1; i != getValue().end(); ++i) {
29 result <<= 8;
30 result |= *i;
Jeff Thompson26c63d62013-07-02 18:00:26 -070031 }
32
Jeff Thompson27cae532013-10-08 12:52:41 -070033 return result;
34}
35
Jeff Thompsond129ac12013-10-11 14:30:12 -070036Name::Component
Jeff Thompsond129ac12013-10-11 14:30:12 -070037Name::Component::fromNumber(uint64_t number)
Jeff Thompson8aac1992013-08-12 17:26:02 -070038{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080039 ptr_lib::shared_ptr<Buffer> value(new Buffer);
Jeff Thompson8aac1992013-08-12 17:26:02 -070040
Jeff Thompsond129ac12013-10-11 14:30:12 -070041 // First encode in little endian.
42 while (number != 0) {
43 value->push_back(number & 0xff);
44 number >>= 8;
45 }
46
47 // Make it big endian.
48 reverse(value->begin(), value->end());
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080049 return Component(value);
Jeff Thompsond129ac12013-10-11 14:30:12 -070050}
51
Alexander Afanasyev848c61a2014-01-03 13:52:04 -080052Name::Component
Jeff Thompsond129ac12013-10-11 14:30:12 -070053Name::Component::fromNumberWithMarker(uint64_t number, uint8_t marker)
54{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080055 ptr_lib::shared_ptr<Buffer> value(new Buffer);
Jeff Thompsond129ac12013-10-11 14:30:12 -070056
57 // Add the leading marker.
58 value->push_back(marker);
Jeff Thompsonb8f1b132013-08-13 11:07:43 -070059
Jeff Thompson8aac1992013-08-12 17:26:02 -070060 // First encode in little endian.
Jeff Thompsond129ac12013-10-11 14:30:12 -070061 while (number != 0) {
62 value->push_back(number & 0xff);
63 number >>= 8;
Jeff Thompson8aac1992013-08-12 17:26:02 -070064 }
65
Jeff Thompson8aac1992013-08-12 17:26:02 -070066 // Make it big endian.
Jeff Thompson995aba52013-09-12 12:04:52 -070067 reverse(value->begin() + 1, value->end());
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080068 return Component(value);
Jeff Thompson25b4e612013-10-10 16:03:24 -070069}
70
71uint64_t
72Name::Component::toNumber() const
73{
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080074 uint64_t result = 0;
75 for (Buffer::const_iterator i = getValue().begin(); i != getValue().end(); ++i) {
76 result <<= 8;
77 result |= *i;
78 }
79
80 return result;
Jeff Thompson25b4e612013-10-10 16:03:24 -070081}
82
Jeff Thompsona98000c2013-12-16 14:40:09 -080083int
84Name::Component::compare(const Name::Component& other) const
85{
86 // Imitate ndn_Exclude_compareComponents.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080087 if (getValue().size() < other.getValue().size())
Jeff Thompsona98000c2013-12-16 14:40:09 -080088 return -1;
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080089 if (getValue().size() > other.getValue().size())
Jeff Thompsona98000c2013-12-16 14:40:09 -080090 return 1;
91
92 // The components are equal length. Just do a byte compare.
Alexander Afanasyevd409d592014-01-28 18:36:38 -080093 return memcmp(getValue().buf(), other.getValue().buf(), getValue().size());
Jeff Thompsona98000c2013-12-16 14:40:09 -080094}
95
Alexander Afanasyevaf283d82014-01-03 13:23:34 -080096// const Block &
97// Name::wireEncode() const
98// {
99
100// }
101
Jeff Thompson25b4e612013-10-10 16:03:24 -0700102void
Jeff Thompson0050abe2013-09-17 12:50:25 -0700103Name::set(const char *uri_cstr)
Jeff Thompson443398d2013-07-02 19:45:46 -0700104{
Jeff Thompson67515bd2013-08-15 17:43:22 -0700105 components_.clear();
106
Jeff Thompson443398d2013-07-02 19:45:46 -0700107 string uri = uri_cstr;
108 trim(uri);
109 if (uri.size() == 0)
110 return;
111
112 size_t iColon = uri.find(':');
113 if (iColon != string::npos) {
114 // Make sure the colon came before a '/'.
115 size_t iFirstSlash = uri.find('/');
116 if (iFirstSlash == string::npos || iColon < iFirstSlash) {
117 // Omit the leading protocol such as ndn:
118 uri.erase(0, iColon + 1);
119 trim(uri);
120 }
121 }
122
123 // Trim the leading slash and possibly the authority.
124 if (uri[0] == '/') {
125 if (uri.size() >= 2 && uri[1] == '/') {
126 // Strip the authority following "//".
127 size_t iAfterAuthority = uri.find('/', 2);
128 if (iAfterAuthority == string::npos)
129 // Unusual case: there was only an authority.
130 return;
131 else {
132 uri.erase(0, iAfterAuthority + 1);
133 trim(uri);
134 }
135 }
136 else {
137 uri.erase(0, 1);
138 trim(uri);
139 }
140 }
141
142 size_t iComponentStart = 0;
143
144 // Unescape the components.
145 while (iComponentStart < uri.size()) {
146 size_t iComponentEnd = uri.find("/", iComponentStart);
147 if (iComponentEnd == string::npos)
148 iComponentEnd = uri.size();
149
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700150 Component component(fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
Jeff Thompson46411c92013-09-13 19:31:25 -0700151 // Ignore illegal components. This also gets rid of a trailing '/'.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800152 if (!component.empty())
Jeff Thompson46411c92013-09-13 19:31:25 -0700153 components_.push_back(Component(component));
Jeff Thompson443398d2013-07-02 19:45:46 -0700154
155 iComponentStart = iComponentEnd + 1;
156 }
157}
158
Jeff Thompson26b0d792013-09-23 16:19:01 -0700159Name&
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.components_.size(); ++i)
167 components_.push_back(name.components_[i]);
168
169 return *this;
170}
171
Alexander Afanasyev594cdb22014-01-03 15:11:33 -0800172Name&
173Name::appendVersion()
174{
175 appendVersion(ndn_getNowMilliseconds());
176 return *this;
177}
178
Jeff Thompsond0159d72013-09-23 13:34:15 -0700179Name
180Name::getSubName(size_t iStartComponent, size_t nComponents) const
181{
182 Name result;
183
Jeff Thompson97223af2013-09-24 17:01:27 -0700184 size_t iEnd = iStartComponent + nComponents;
185 for (size_t i = iStartComponent; i < iEnd && i < components_.size(); ++i)
Jeff Thompsond0159d72013-09-23 13:34:15 -0700186 result.components_.push_back(components_[i]);
187
188 return result;
189}
190
191Name
192Name::getSubName(size_t iStartComponent) const
193{
194 Name result;
195
Jeff Thompson97223af2013-09-24 17:01:27 -0700196 for (size_t i = iStartComponent; i < components_.size(); ++i)
Jeff Thompsond0159d72013-09-23 13:34:15 -0700197 result.components_.push_back(components_[i]);
198
199 return result;
200}
201
Jeff Thompson0050abe2013-09-17 12:50:25 -0700202bool
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700203Name::equals(const Name& name) const
204{
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700205 if (components_.size() != name.components_.size())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700206 return false;
207
208 for (size_t i = 0; i < components_.size(); ++i) {
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800209 if (components_[i].getValue() != name.components_[i].getValue())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700210 return false;
211 }
212
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700213 return true;
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700214}
215
216bool
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800217Name::isPrefixOf(const Name& name) const
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700218{
219 // Imitate ndn_Name_match.
220
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700221 // This name is longer than the name we are checking it against.
222 if (components_.size() > name.components_.size())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700223 return false;
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700224
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700225 // Check if at least one of given components doesn't match.
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700226 for (size_t i = 0; i < components_.size(); ++i) {
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800227 if (components_[i].getValue() != name.components_[i].getValue())
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700228 return false;
229 }
230
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700231 return true;
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700232}
233
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800234Name::Component
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700235Name::fromEscapedString(const char *escapedString, size_t beginOffset, size_t endOffset)
236{
237 string trimmedString(escapedString + beginOffset, escapedString + endOffset);
238 trim(trimmedString);
239 string value = unescape(trimmedString);
240
241 if (value.find_first_not_of(".") == string::npos) {
242 // Special case for component of only periods.
243 if (value.size() <= 2)
244 // Zero, one or two periods is illegal. Ignore this component.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800245 return Component();
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700246 else
247 // Remove 3 periods.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800248 return Component((const uint8_t *)&value[3], value.size() - 3);
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700249 }
250 else
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800251 return Component((const uint8_t *)&value[0], value.size());
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700252}
253
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800254Name::Component
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700255Name::fromEscapedString(const char *escapedString)
256{
257 return fromEscapedString(escapedString, 0, ::strlen(escapedString));
258}
259
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800260void
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800261Name::toEscapedString(const uint8_t *value, size_t valueSize, std::ostream& result)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700262{
263 bool gotNonDot = false;
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800264 for (unsigned i = 0; i < valueSize; ++i) {
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700265 if (value[i] != 0x2e) {
266 gotNonDot = true;
267 break;
268 }
269 }
270 if (!gotNonDot) {
271 // Special case for component of zero or more periods. Add 3 periods.
272 result << "...";
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800273 for (size_t i = 0; i < valueSize; ++i)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700274 result << '.';
275 }
276 else {
277 // In case we need to escape, set to upper case hex and save the previous flags.
278 ios::fmtflags saveFlags = result.flags(ios::hex | ios::uppercase);
279
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800280 for (size_t i = 0; i < valueSize; ++i) {
Jeff Thompson10ad12a2013-09-24 16:19:11 -0700281 uint8_t x = value[i];
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700282 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
Jeff Thompsonf68a74a2013-11-20 15:16:11 -0800283 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
284 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
285 x == 0x2e || x == 0x5f)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700286 result << x;
287 else {
288 result << '%';
289 if (x < 16)
290 result << '0';
291 result << (unsigned int)x;
292 }
293 }
294
295 // Restore.
296 result.flags(saveFlags);
297 }
298}
299
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800300int
301Name::compare(const Name& other) const
Jeff Thompson82568ad2013-12-17 15:17:40 -0800302{
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800303 for (size_t i = 0; i < size() && i < other.size(); ++i) {
304 int comparison = components_[i].compare(other.components_[i]);
305 if (comparison == 0)
Jeff Thompson82568ad2013-12-17 15:17:40 -0800306 // The components at this index are equal, so check the next components.
307 continue;
308
309 // Otherwise, the result is based on the components at this index.
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800310 return comparison;
Jeff Thompson82568ad2013-12-17 15:17:40 -0800311 }
312
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800313 // The components up to min(this.size(), other.size()) are equal, so the shorter name is less.
314 if (size() < other.size())
315 return -1;
316 else if (size() > other.size())
317 return 1;
318 else
319 return 0;
Jeff Thompson82568ad2013-12-17 15:17:40 -0800320}
321
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800322std::ostream&
323operator << (std::ostream& os, const Name& name)
324{
325 if (name.empty())
326 {
327 os << "/";
328 }
329 else
330 {
331 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
332 os << "/";
333 i->toEscapedString(os);
334 }
335 }
336
337 return os;
338}
Jeff Thompson82568ad2013-12-17 15:17:40 -0800339
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800340const Block &
341Name::wireEncode() const
342{
343 if (wire_.hasWire())
344 return wire_;
345
346 wire_ = Block(Tlv::Name);
347 for (Name::const_iterator i = begin(); i != end(); i++) {
348 OBufferStream os;
349 Tlv::writeVarNumber(os, Tlv::NameComponent);
350 Tlv::writeVarNumber(os, i->getValue().size());
351 os.write(reinterpret_cast<const char*>(i->getValue().buf()), i->getValue().size());
352
353 wire_.push_back(Block(os.buf()));
354 }
355
356 wire_.encode();
357 return wire_;
358}
359
360void
361Name::wireDecode(const Block &wire)
362{
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800363 clear();
364
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800365 wire_ = wire;
366 wire_.parse();
367
Alexander Afanasyev7b4a7fc2014-01-10 10:11:07 -0800368 components_.clear();
369 components_.reserve(wire_.getAll().size());
370
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800371 for (Block::element_const_iterator i = wire_.getAll().begin();
372 i != wire_.getAll().end();
373 ++i)
374 {
375 append(i->value(), i->value_size());
376 }
377}
Jeff Thompson9c41dfe2013-06-27 12:10:25 -0700378}