blob: fe1f73927fe20c4e085206014c3d9c3fb2957fa1 [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>
Alexander Afanasyev1e0a0772014-01-28 20:07:07 -080011#include <cstring>
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080012#include "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 Afanasyev1e0a0772014-01-28 20:07:07 -080093 return std::memcmp(getValue().buf(), other.getValue().buf(), getValue().size());
Jeff Thompsona98000c2013-12-16 14:40:09 -080094}
95
Wentao Shang77949212014-02-01 23:42:24 -080096inline size_t
97Name::Component::wireEncode (EncodingBuffer& blk)
98{
99 size_t total_len = 0;
100 total_len += blk.prependBuffer (*value_);
101 total_len += blk.prependVarNumber (value_->size ());
102 total_len += blk.prependVarNumber (Tlv::NameComponent);
103 return total_len;
104}
105
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800106// const Block &
107// Name::wireEncode() const
108// {
109
110// }
111
Jeff Thompson25b4e612013-10-10 16:03:24 -0700112void
Jeff Thompson0050abe2013-09-17 12:50:25 -0700113Name::set(const char *uri_cstr)
Jeff Thompson443398d2013-07-02 19:45:46 -0700114{
Jeff Thompson67515bd2013-08-15 17:43:22 -0700115 components_.clear();
116
Jeff Thompson443398d2013-07-02 19:45:46 -0700117 string uri = uri_cstr;
118 trim(uri);
119 if (uri.size() == 0)
120 return;
121
122 size_t iColon = uri.find(':');
123 if (iColon != string::npos) {
124 // Make sure the colon came before a '/'.
125 size_t iFirstSlash = uri.find('/');
126 if (iFirstSlash == string::npos || iColon < iFirstSlash) {
127 // Omit the leading protocol such as ndn:
128 uri.erase(0, iColon + 1);
129 trim(uri);
130 }
131 }
132
133 // Trim the leading slash and possibly the authority.
134 if (uri[0] == '/') {
135 if (uri.size() >= 2 && uri[1] == '/') {
136 // Strip the authority following "//".
137 size_t iAfterAuthority = uri.find('/', 2);
138 if (iAfterAuthority == string::npos)
139 // Unusual case: there was only an authority.
140 return;
141 else {
142 uri.erase(0, iAfterAuthority + 1);
143 trim(uri);
144 }
145 }
146 else {
147 uri.erase(0, 1);
148 trim(uri);
149 }
150 }
151
152 size_t iComponentStart = 0;
153
154 // Unescape the components.
155 while (iComponentStart < uri.size()) {
156 size_t iComponentEnd = uri.find("/", iComponentStart);
157 if (iComponentEnd == string::npos)
158 iComponentEnd = uri.size();
159
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700160 Component component(fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
Jeff Thompson46411c92013-09-13 19:31:25 -0700161 // Ignore illegal components. This also gets rid of a trailing '/'.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800162 if (!component.empty())
Jeff Thompson46411c92013-09-13 19:31:25 -0700163 components_.push_back(Component(component));
Jeff Thompson443398d2013-07-02 19:45:46 -0700164
165 iComponentStart = iComponentEnd + 1;
166 }
167}
168
Jeff Thompson26b0d792013-09-23 16:19:01 -0700169Name&
170Name::append(const Name& name)
171{
172 if (&name == this)
173 // Copying from this name, so need to make a copy first.
174 return append(Name(name));
175
176 for (size_t i = 0; i < name.components_.size(); ++i)
177 components_.push_back(name.components_[i]);
178
179 return *this;
180}
181
Alexander Afanasyev594cdb22014-01-03 15:11:33 -0800182Name&
183Name::appendVersion()
184{
185 appendVersion(ndn_getNowMilliseconds());
186 return *this;
187}
188
Jeff Thompsond0159d72013-09-23 13:34:15 -0700189Name
190Name::getSubName(size_t iStartComponent, size_t nComponents) const
191{
192 Name result;
193
Jeff Thompson97223af2013-09-24 17:01:27 -0700194 size_t iEnd = iStartComponent + nComponents;
195 for (size_t i = iStartComponent; i < iEnd && i < components_.size(); ++i)
Jeff Thompsond0159d72013-09-23 13:34:15 -0700196 result.components_.push_back(components_[i]);
197
198 return result;
199}
200
201Name
202Name::getSubName(size_t iStartComponent) const
203{
204 Name result;
205
Jeff Thompson97223af2013-09-24 17:01:27 -0700206 for (size_t i = iStartComponent; i < components_.size(); ++i)
Jeff Thompsond0159d72013-09-23 13:34:15 -0700207 result.components_.push_back(components_[i]);
208
209 return result;
210}
211
Jeff Thompson0050abe2013-09-17 12:50:25 -0700212bool
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700213Name::equals(const Name& name) const
214{
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700215 if (components_.size() != name.components_.size())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700216 return false;
217
218 for (size_t i = 0; i < components_.size(); ++i) {
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800219 if (components_[i].getValue() != name.components_[i].getValue())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700220 return false;
221 }
222
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700223 return true;
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700224}
225
226bool
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800227Name::isPrefixOf(const Name& name) const
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700228{
229 // Imitate ndn_Name_match.
230
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700231 // This name is longer than the name we are checking it against.
232 if (components_.size() > name.components_.size())
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700233 return false;
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700234
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700235 // Check if at least one of given components doesn't match.
Jeff Thompson3c2ab012013-10-02 14:18:16 -0700236 for (size_t i = 0; i < components_.size(); ++i) {
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800237 if (components_[i].getValue() != name.components_[i].getValue())
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700238 return false;
239 }
240
Jeff Thompsone589c3f2013-10-12 17:30:50 -0700241 return true;
Jeff Thompsoncc35cd42013-08-20 12:23:14 -0700242}
243
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800244Name::Component
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700245Name::fromEscapedString(const char *escapedString, size_t beginOffset, size_t endOffset)
246{
247 string trimmedString(escapedString + beginOffset, escapedString + endOffset);
248 trim(trimmedString);
249 string value = unescape(trimmedString);
250
251 if (value.find_first_not_of(".") == string::npos) {
252 // Special case for component of only periods.
253 if (value.size() <= 2)
254 // Zero, one or two periods is illegal. Ignore this component.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800255 return Component();
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700256 else
257 // Remove 3 periods.
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800258 return Component((const uint8_t *)&value[3], value.size() - 3);
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700259 }
260 else
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800261 return Component((const uint8_t *)&value[0], value.size());
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700262}
263
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800264Name::Component
Jeff Thompsond8e53e62013-10-29 16:59:49 -0700265Name::fromEscapedString(const char *escapedString)
266{
267 return fromEscapedString(escapedString, 0, ::strlen(escapedString));
268}
269
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800270void
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800271Name::toEscapedString(const uint8_t *value, size_t valueSize, std::ostream& result)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700272{
273 bool gotNonDot = false;
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800274 for (unsigned i = 0; i < valueSize; ++i) {
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700275 if (value[i] != 0x2e) {
276 gotNonDot = true;
277 break;
278 }
279 }
280 if (!gotNonDot) {
281 // Special case for component of zero or more periods. Add 3 periods.
282 result << "...";
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800283 for (size_t i = 0; i < valueSize; ++i)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700284 result << '.';
285 }
286 else {
287 // In case we need to escape, set to upper case hex and save the previous flags.
288 ios::fmtflags saveFlags = result.flags(ios::hex | ios::uppercase);
289
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800290 for (size_t i = 0; i < valueSize; ++i) {
Jeff Thompson10ad12a2013-09-24 16:19:11 -0700291 uint8_t x = value[i];
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700292 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
Jeff Thompsonf68a74a2013-11-20 15:16:11 -0800293 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
294 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
295 x == 0x2e || x == 0x5f)
Jeff Thompsonec7789a2013-08-21 11:08:36 -0700296 result << x;
297 else {
298 result << '%';
299 if (x < 16)
300 result << '0';
301 result << (unsigned int)x;
302 }
303 }
304
305 // Restore.
306 result.flags(saveFlags);
307 }
308}
309
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800310int
311Name::compare(const Name& other) const
Jeff Thompson82568ad2013-12-17 15:17:40 -0800312{
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800313 for (size_t i = 0; i < size() && i < other.size(); ++i) {
314 int comparison = components_[i].compare(other.components_[i]);
315 if (comparison == 0)
Jeff Thompson82568ad2013-12-17 15:17:40 -0800316 // The components at this index are equal, so check the next components.
317 continue;
318
319 // Otherwise, the result is based on the components at this index.
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800320 return comparison;
Jeff Thompson82568ad2013-12-17 15:17:40 -0800321 }
322
Jeff Thompsonafc45a92014-01-15 12:42:45 -0800323 // The components up to min(this.size(), other.size()) are equal, so the shorter name is less.
324 if (size() < other.size())
325 return -1;
326 else if (size() > other.size())
327 return 1;
328 else
329 return 0;
Jeff Thompson82568ad2013-12-17 15:17:40 -0800330}
331
Alexander Afanasyevaf283d82014-01-03 13:23:34 -0800332std::ostream&
333operator << (std::ostream& os, const Name& name)
334{
335 if (name.empty())
336 {
337 os << "/";
338 }
339 else
340 {
341 for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
342 os << "/";
343 i->toEscapedString(os);
344 }
345 }
346
347 return os;
348}
Jeff Thompson82568ad2013-12-17 15:17:40 -0800349
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800350const Block &
351Name::wireEncode() const
352{
353 if (wire_.hasWire())
354 return wire_;
355
356 wire_ = Block(Tlv::Name);
357 for (Name::const_iterator i = begin(); i != end(); i++) {
358 OBufferStream os;
359 Tlv::writeVarNumber(os, Tlv::NameComponent);
360 Tlv::writeVarNumber(os, i->getValue().size());
361 os.write(reinterpret_cast<const char*>(i->getValue().buf()), i->getValue().size());
362
363 wire_.push_back(Block(os.buf()));
364 }
365
366 wire_.encode();
367 return wire_;
368}
369
370void
371Name::wireDecode(const Block &wire)
372{
Alexander Afanasyev2a742762013-12-28 14:09:46 -0800373 clear();
374
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800375 wire_ = wire;
376 wire_.parse();
377
Alexander Afanasyev7b4a7fc2014-01-10 10:11:07 -0800378 components_.clear();
379 components_.reserve(wire_.getAll().size());
380
Alexander Afanasyev848c61a2014-01-03 13:52:04 -0800381 for (Block::element_const_iterator i = wire_.getAll().begin();
382 i != wire_.getAll().end();
383 ++i)
384 {
385 append(i->value(), i->value_size());
386 }
387}
Wentao Shang77949212014-02-01 23:42:24 -0800388
389
390size_t
391Name::wireEncode (EncodingBuffer& blk)
392{
393 size_t total_len = 0;
394
395 for (std::vector<Component>::reverse_iterator i = components_.rbegin ();
396 i != components_.rend ();
397 ++i)
398 {
399 total_len += i->wireEncode (blk);
400 }
401
402 total_len += blk.prependVarNumber (total_len);
403 total_len += blk.prependVarNumber (Tlv::Name);
404 return total_len;
Jeff Thompson9c41dfe2013-06-27 12:10:25 -0700405}
Wentao Shang77949212014-02-01 23:42:24 -0800406
407} // namespace ndn