blob: b5cd444ec9baeb3bbfc27911a3e9270f656fc18e [file] [log] [blame]
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
5 * @author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
6 * @author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
7 * See COPYING for copyright and distribution information.
8 */
9
10#ifndef NDN_NAME_COMPONENT_HPP
11#define NDN_NAME_COMPONENT_HPP
12
13#include "common.hpp"
14#include "encoding/block.hpp"
15#include "encoding/encoding-buffer.hpp"
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070016#include "util/string-helper.hpp"
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080017
18namespace ndn {
19namespace name {
20
21/**
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -070022 * @brief Component holds a read-only name component value.
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080023 */
24class Component : public Block
25{
26public:
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070027 /**
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070028 * @brief Error that can be thrown from name::Component
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070029 */
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070030 class Error : public Block::Error
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070031 {
32 public:
33 explicit
34 Error(const std::string& what)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070035 : Block::Error(what)
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070036 {
37 }
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070038 };
39
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080040 /**
41 * Create a new Name::Component with a null value.
42 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070043 Component();
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080044
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080045 /**
46 * @brief Directly create component from wire block
47 *
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070048 * Any block can be implicitly converted to name::Component
49 *
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070050 * @throws Error if wire.type() is not Tlv::Component
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080051 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070052 Component(const Block& wire);
53
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080054 /**
55 * Create a new Name::Component, taking another pointer to the Blob value.
56 * @param value A blob with a pointer to an immutable array. The pointer is copied.
57 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070058 explicit
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070059 Component(const ConstBufferPtr& buffer);
60
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080061 /**
62 * Create a new Name::Component, copying the given value.
63 * @param value The value byte array.
64 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070065 explicit
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070066 Component(const Buffer& value);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080067
68 /**
69 * Create a new Name::Component, copying the given value.
70 * @param value Pointer to the value byte array.
71 * @param valueLen Length of value.
72 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070073 Component(const uint8_t* value, size_t valueLen);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080074
75 template<class InputIterator>
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070076 Component(InputIterator begin, InputIterator end);
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080077
78 explicit
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070079 Component(const char* str);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080080
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080081 explicit
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070082 Component(const std::string& str);
83
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080084 /**
85 * @brief Fast encoding or block size estimation
86 */
87 template<bool T>
88 size_t
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070089 wireEncode(EncodingImpl<T>& block) const;
90
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080091 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070092 * @brief Encode to a wire format
93 */
94 inline const Block&
95 wireEncode() const;
96
97 /**
98 * @brief Decode from the wire format
99 */
100 inline void
101 wireDecode(const Block& wire);
102
103 /**
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800104 * Make a Blob value by decoding the escapedString between beginOffset and endOffset according to the NDN URI Scheme.
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700105 * If the escaped string is "", "." or ".." then return a Blob with a null pointer,
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800106 * which means the component should be skipped in a URI name.
107 * @param escapedString The escaped string. It does not need to be null-terminated because we only scan to endOffset.
108 * @param beginOffset The offset in escapedString of the beginning of the portion to decode.
109 * @param endOffset The offset in escapedString of the end of the portion to decode.
110 * @return The Blob value. If the escapedString is not a valid escaped component, then the Blob is a null pointer.
111 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700112 static Component
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700113 fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800114
115 /**
116 * Make a Blob value by decoding the escapedString according to the NDN URI Scheme.
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700117 * If the escaped string is "", "." or ".." then return a Blob with a null pointer,
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800118 * which means the component should be skipped in a URI name.
119 * @param escapedString The null-terminated escaped string.
120 * @return The Blob value. If the escapedString is not a valid escaped component, then the Blob is a null pointer.
121 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700122 static Component
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700123 fromEscapedString(const char* escapedString)
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800124 {
125 return fromEscapedString(escapedString, 0, ::strlen(escapedString));
126 }
127
128 /**
129 * Make a Blob value by decoding the escapedString according to the NDN URI Scheme.
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700130 * If the escaped string is "", "." or ".." then return a Blob with a null pointer,
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800131 * which means the component should be skipped in a URI name.
132 * @param escapedString The escaped string.
133 * @return The Blob value. If the escapedString is not a valid escaped component, then the Blob is a null pointer.
134 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700135 static Component
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800136 fromEscapedString(const std::string& escapedString)
137 {
138 return fromEscapedString(escapedString.c_str());
139 }
140
141 /**
142 * Write the value to result, escaping characters according to the NDN URI Scheme.
143 * This also adds "..." to a value with zero or more ".".
144 * @param value the buffer with the value to escape
145 * @param result the string stream to write to.
146 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700147 void
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800148 toEscapedString(std::ostream& result) const;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700149
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800150 /**
151 * Convert the value by escaping characters according to the NDN URI Scheme.
152 * This also adds "..." to a value with zero or more ".".
153 * @param value the buffer with the value to escape
154 * @return The escaped string.
155 */
156 inline std::string
157 toEscapedString() const
158 {
159 std::ostringstream result;
160 toEscapedString(result);
161 return result.str();
162 }
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -0800163
164 inline void
165 toUri(std::ostream& result) const
166 {
167 return toEscapedString(result);
168 }
169
170 inline std::string
171 toUri() const
172 {
173 return toEscapedString();
174 }
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700175
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800176 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700177 * @brief Interpret this name component as nonNegativeInteger
178 *
179 * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
180 *
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800181 * @return The integer number.
182 */
183 uint64_t
184 toNumber() const;
185
186 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700187 * @brief An alias for toNumber()
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800188 */
189 uint64_t
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700190 toVersion() const;
191
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800192 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700193 * @brief An alias for toNumber()
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800194 */
195 uint64_t
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700196 toSegment() const;
197
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800198 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700199 * @brief Create a component encoded as nonNegativeInteger
200 *
201 * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
202 *
203 * @param number The non-negative number
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800204 * @return The component value.
205 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700206 static Component
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800207 fromNumber(uint64_t number);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800208
209 /**
210 * Check if this is the same component as other.
211 * @param other The other Component to compare with.
212 * @return true if the components are equal, otherwise false.
213 */
214 bool
215 equals(const Component& other) const
216 {
217 if (value_size() != other.value_size())
218 return false;
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800219 if (value_size() == 0 /* == other.value_size()*/)
220 return true;
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800221
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800222 // somehow, behavior is wrong on OSX 10.9 when component is empty
223 // (probably some bug in STL...)
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800224 return std::equal(value_begin(), value_end(), other.value_begin());
225 }
226
227 bool
228 empty() const
229 {
230 return !hasValue();
231 }
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700232
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800233 /**
234 * Check if this is the same component as other.
235 * @param other The other Component to compare with.
236 * @return true if the components are equal, otherwise false.
237 */
238 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700239 operator==(const Component& other) const { return equals(other); }
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800240
241 /**
242 * Check if this is not the same component as other.
243 * @param other The other Component to compare with.
244 * @return true if the components are not equal, otherwise false.
245 */
246 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700247 operator!=(const Component& other) const { return !equals(other); }
248
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800249 /**
250 * Compare this to the other Component using NDN canonical ordering.
251 * @param other The other Component to compare with.
252 * @return 0 If they compare equal, -1 if *this comes before other in the canonical ordering, or
253 * 1 if *this comes after other in the canonical ordering.
254 *
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700255 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800256 */
257 int
258 compare(const Component& other) const;
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800259
260 /**
261 * Return true if this is less than or equal to the other Component in the NDN canonical ordering.
262 * @param other The other Component to compare with.
263 *
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700264 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800265 */
266 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700267 operator<=(const Component& other) const { return compare(other) <= 0; }
268
269 /**
270 * Return true if this is less than the other Component in the NDN canonical ordering.
271 * @param other The other Component to compare with.
272 *
273 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
274 */
275 bool
276 operator<(const Component& other) const { return compare(other) < 0; }
277
278 /**
279 * Return true if this is less than or equal to the other Component in the NDN canonical ordering.
280 * @param other The other Component to compare with.
281 *
282 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
283 */
284 bool
285 operator>=(const Component& other) const { return compare(other) >= 0; }
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800286
287 /**
288 * Return true if this is greater than the other Component in the NDN canonical ordering.
289 * @param other The other Component to compare with.
290 *
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700291 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800292 */
293 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700294 operator>(const Component& other) const { return compare(other) > 0; }
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800295
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700296 //
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800297 // !!! MUST NOT INCLUDE ANY DATA HERE !!!
298 //
299 // This class is just a helper and is directly reinterpret_cast'ed from Block
300};
301
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700302inline std::ostream&
303operator << (std::ostream& os, const Component& component)
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800304{
305 component.toEscapedString(os);
306 return os;
307}
308
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700309inline
310Component::Component()
311 : Block(Tlv::NameComponent)
312{
313}
314
315inline
316Component::Component(const Block& wire)
317 : Block(wire)
318{
319 if (type() != Tlv::NameComponent)
320 throw Error("Constructing name component from non name component TLV wire block");
321}
322
323inline
324Component::Component(const ConstBufferPtr& buffer)
325 : Block (Tlv::NameComponent, buffer)
326{
327}
328
329inline
330Component::Component(const Buffer& value)
331 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(value)))
332{
333}
334
335inline
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700336Component::Component(const uint8_t* value, size_t valueLen)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700337 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(value, valueLen)))
338{
339}
340
341template<class InputIterator>
342inline
343Component::Component(InputIterator begin, InputIterator end)
344 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(begin, end)))
345{
346}
347
348inline
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700349Component::Component(const char* str)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700350 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(str, ::strlen(str))))
351{
352}
353
354inline
355Component::Component(const std::string& str)
356 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(str.begin(), str.end())))
357{
358}
359
360
361inline Component
362Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
363{
364 std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
365 trim(trimmedString);
366 std::string value = unescape(trimmedString);
367
368 if (value.find_first_not_of(".") == std::string::npos) {
369 // Special case for component of only periods.
370 if (value.size() <= 2)
371 // Zero, one or two periods is illegal. Ignore this component.
372 return Component();
373 else
374 // Remove 3 periods.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700375 return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700376 }
377 else
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700378 return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700379}
380
381
382inline void
383Component::toEscapedString(std::ostream& result) const
384{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700385 const uint8_t* valuePtr = value();
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700386 size_t valueSize = value_size();
387
388 bool gotNonDot = false;
389 for (unsigned i = 0; i < valueSize; ++i) {
390 if (valuePtr[i] != 0x2e) {
391 gotNonDot = true;
392 break;
393 }
394 }
395 if (!gotNonDot) {
396 // Special case for component of zero or more periods. Add 3 periods.
397 result << "...";
398 for (size_t i = 0; i < valueSize; ++i)
399 result << '.';
400 }
401 else {
402 // In case we need to escape, set to upper case hex and save the previous flags.
403 std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
404
405 for (size_t i = 0; i < valueSize; ++i) {
406 uint8_t x = valuePtr[i];
407 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
408 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
409 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
410 x == 0x2e || x == 0x5f)
411 result << x;
412 else {
413 result << '%';
414 if (x < 16)
415 result << '0';
416 result << (unsigned int)x;
417 }
418 }
419
420 // Restore.
421 result.flags(saveFlags);
422 }
423}
424
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700425
426inline Component
427Component::fromNumber(uint64_t number)
428{
429 /// \todo Change to Tlv::NumberComponent
430 return nonNegativeIntegerBlock(Tlv::NameComponent, number);
431}
432
433
434inline uint64_t
435Component::toNumber() const
436{
437 /// \todo Check if Component is of Tlv::NumberComponent type
438 return readNonNegativeInteger(static_cast<const Block&>(*this));
439}
440
441
442inline uint64_t
443Component::toVersion() const
444{
445 return toNumber();
446}
447
448inline uint64_t
449Component::toSegment() const
450{
451 return toNumber();
452}
453
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700454inline int
455Component::compare(const Component& other) const
456{
457 // Imitate ndn_Exclude_compareComponents.
458 if (value_size() < other.value_size())
459 return -1;
460 if (value_size() > other.value_size())
461 return 1;
462
463 if (value_size() == 0)
464 return 0;
465
466 // The components are equal length. Just do a byte compare.
467 return std::memcmp(value(), other.value(), value_size());
468}
469
470
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800471template<bool T>
472inline size_t
473Component::wireEncode(EncodingImpl<T>& block) const
474{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700475 size_t totalLength = 0;
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800476 if (value_size() > 0)
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700477 totalLength += block.prependByteArray (value(), value_size());
478 totalLength += block.prependVarNumber (value_size());
479 totalLength += block.prependVarNumber (Tlv::NameComponent);
480 return totalLength;
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800481}
482
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700483/**
484 * @brief Encode to a wire format
485 */
486inline const Block&
487Component::wireEncode() const
488{
489 if (this->hasWire())
490 return *this;
491
492 EncodingEstimator estimator;
493 size_t estimatedSize = wireEncode(estimator);
494
495 EncodingBuffer buffer(estimatedSize, 0);
496 wireEncode(buffer);
497
498 const_cast<Component&>(*this) = buffer.block();
499 return *this;
500}
501
502/**
503 * @brief Decode from the wire format
504 */
505inline void
506Component::wireDecode(const Block& wire)
507{
508 if (wire.type() != Tlv::NameComponent)
509 throw Error("wireDecode name component from non name component TLV wire block");
510
511 *this = wire;
512}
513
514
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800515} // namespace name
516} // namespace ndn
517
518#endif // NDN_NAME_COMPONENT_HPP