blob: 9c98e3af28265b83f25ec2347d18756c8764760e [file] [log] [blame]
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Jeff Thompson <jefft0@remap.ucla.edu>
13 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
14 * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080015 */
16
17#ifndef NDN_NAME_COMPONENT_HPP
18#define NDN_NAME_COMPONENT_HPP
19
20#include "common.hpp"
21#include "encoding/block.hpp"
22#include "encoding/encoding-buffer.hpp"
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070023#include "util/string-helper.hpp"
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080024
25namespace ndn {
26namespace name {
27
28/**
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -070029 * @brief Component holds a read-only name component value.
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080030 */
31class Component : public Block
32{
33public:
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070034 /**
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070035 * @brief Error that can be thrown from name::Component
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070036 */
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070037 class Error : public Block::Error
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070038 {
39 public:
40 explicit
41 Error(const std::string& what)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070042 : Block::Error(what)
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070043 {
44 }
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070045 };
46
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080047 /**
48 * Create a new Name::Component with a null value.
49 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070050 Component();
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080051
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080052 /**
53 * @brief Directly create component from wire block
54 *
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070055 * Any block can be implicitly converted to name::Component
56 *
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070057 * @throws Error if wire.type() is not Tlv::Component
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080058 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070059 Component(const Block& wire);
60
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080061 /**
62 * Create a new Name::Component, taking another pointer to the Blob value.
63 * @param value A blob with a pointer to an immutable array. The pointer is copied.
64 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070065 explicit
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070066 Component(const ConstBufferPtr& buffer);
67
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080068 /**
69 * Create a new Name::Component, copying the given value.
70 * @param value The value byte array.
71 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070072 explicit
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070073 Component(const Buffer& value);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080074
75 /**
76 * Create a new Name::Component, copying the given value.
77 * @param value Pointer to the value byte array.
78 * @param valueLen Length of value.
79 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070080 Component(const uint8_t* value, size_t valueLen);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080081
82 template<class InputIterator>
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070083 Component(InputIterator begin, InputIterator end);
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080084
85 explicit
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070086 Component(const char* str);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080087
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -080088 explicit
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070089 Component(const std::string& str);
90
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080091 /**
92 * @brief Fast encoding or block size estimation
93 */
94 template<bool T>
95 size_t
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -070096 wireEncode(EncodingImpl<T>& block) const;
97
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -080098 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070099 * @brief Encode to a wire format
100 */
101 inline const Block&
102 wireEncode() const;
103
104 /**
105 * @brief Decode from the wire format
106 */
107 inline void
108 wireDecode(const Block& wire);
109
110 /**
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800111 * 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 -0700112 * If the escaped string is "", "." or ".." then return a Blob with a null pointer,
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800113 * which means the component should be skipped in a URI name.
114 * @param escapedString The escaped string. It does not need to be null-terminated because we only scan to endOffset.
115 * @param beginOffset The offset in escapedString of the beginning of the portion to decode.
116 * @param endOffset The offset in escapedString of the end of the portion to decode.
117 * @return The Blob value. If the escapedString is not a valid escaped component, then the Blob is a null pointer.
118 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700119 static Component
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700120 fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800121
122 /**
123 * Make a Blob value by decoding the escapedString according to the NDN URI Scheme.
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700124 * If the escaped string is "", "." or ".." then return a Blob with a null pointer,
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800125 * which means the component should be skipped in a URI name.
126 * @param escapedString The null-terminated escaped string.
127 * @return The Blob value. If the escapedString is not a valid escaped component, then the Blob is a null pointer.
128 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700129 static Component
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700130 fromEscapedString(const char* escapedString)
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800131 {
132 return fromEscapedString(escapedString, 0, ::strlen(escapedString));
133 }
134
135 /**
136 * Make a Blob value by decoding the escapedString according to the NDN URI Scheme.
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700137 * If the escaped string is "", "." or ".." then return a Blob with a null pointer,
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800138 * which means the component should be skipped in a URI name.
139 * @param escapedString The escaped string.
140 * @return The Blob value. If the escapedString is not a valid escaped component, then the Blob is a null pointer.
141 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700142 static Component
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800143 fromEscapedString(const std::string& escapedString)
144 {
145 return fromEscapedString(escapedString.c_str());
146 }
147
148 /**
149 * Write the value to result, escaping characters according to the NDN URI Scheme.
150 * This also adds "..." to a value with zero or more ".".
151 * @param value the buffer with the value to escape
152 * @param result the string stream to write to.
153 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700154 void
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800155 toEscapedString(std::ostream& result) const;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700156
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800157 /**
158 * Convert the value by escaping characters according to the NDN URI Scheme.
159 * This also adds "..." to a value with zero or more ".".
160 * @param value the buffer with the value to escape
161 * @return The escaped string.
162 */
163 inline std::string
164 toEscapedString() const
165 {
166 std::ostringstream result;
167 toEscapedString(result);
168 return result.str();
169 }
Alexander Afanasyev52eb20d2014-02-06 18:25:54 -0800170
171 inline void
172 toUri(std::ostream& result) const
173 {
174 return toEscapedString(result);
175 }
176
177 inline std::string
178 toUri() const
179 {
180 return toEscapedString();
181 }
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700182
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800183 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700184 * @brief Interpret this name component as nonNegativeInteger
185 *
186 * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
187 *
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800188 * @return The integer number.
189 */
190 uint64_t
191 toNumber() const;
192
193 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700194 * @brief An alias for toNumber()
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800195 */
196 uint64_t
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700197 toVersion() const;
198
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800199 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700200 * @brief An alias for toNumber()
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800201 */
202 uint64_t
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700203 toSegment() const;
204
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800205 /**
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700206 * @brief Create a component encoded as nonNegativeInteger
207 *
208 * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
209 *
210 * @param number The non-negative number
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800211 * @return The component value.
212 */
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700213 static Component
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800214 fromNumber(uint64_t number);
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800215
216 /**
217 * Check if this is the same component as other.
218 * @param other The other Component to compare with.
219 * @return true if the components are equal, otherwise false.
220 */
221 bool
222 equals(const Component& other) const
223 {
224 if (value_size() != other.value_size())
225 return false;
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800226 if (value_size() == 0 /* == other.value_size()*/)
227 return true;
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800228
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800229 // somehow, behavior is wrong on OSX 10.9 when component is empty
230 // (probably some bug in STL...)
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800231 return std::equal(value_begin(), value_end(), other.value_begin());
232 }
233
234 bool
235 empty() const
236 {
237 return !hasValue();
238 }
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700239
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800240 /**
241 * Check if this is the same component as other.
242 * @param other The other Component to compare with.
243 * @return true if the components are equal, otherwise false.
244 */
245 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700246 operator==(const Component& other) const { return equals(other); }
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800247
248 /**
249 * Check if this is not the same component as other.
250 * @param other The other Component to compare with.
251 * @return true if the components are not equal, otherwise false.
252 */
253 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700254 operator!=(const Component& other) const { return !equals(other); }
255
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800256 /**
257 * Compare this to the other Component using NDN canonical ordering.
258 * @param other The other Component to compare with.
259 * @return 0 If they compare equal, -1 if *this comes before other in the canonical ordering, or
260 * 1 if *this comes after other in the canonical ordering.
261 *
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700262 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800263 */
264 int
265 compare(const Component& other) const;
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800266
267 /**
268 * Return true if this is less than or equal to the other Component in the NDN canonical ordering.
269 * @param other The other Component to compare with.
270 *
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700271 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800272 */
273 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700274 operator<=(const Component& other) const { return compare(other) <= 0; }
275
276 /**
277 * Return true if this is less than the other Component in the NDN canonical ordering.
278 * @param other The other Component to compare with.
279 *
280 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
281 */
282 bool
283 operator<(const Component& other) const { return compare(other) < 0; }
284
285 /**
286 * Return true if this is less than or equal to the other Component in the NDN canonical ordering.
287 * @param other The other Component to compare with.
288 *
289 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
290 */
291 bool
292 operator>=(const Component& other) const { return compare(other) >= 0; }
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800293
294 /**
295 * Return true if this is greater than the other Component in the NDN canonical ordering.
296 * @param other The other Component to compare with.
297 *
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700298 * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800299 */
300 bool
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700301 operator>(const Component& other) const { return compare(other) > 0; }
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800302
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700303 //
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800304 // !!! MUST NOT INCLUDE ANY DATA HERE !!!
305 //
306 // This class is just a helper and is directly reinterpret_cast'ed from Block
307};
308
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700309inline std::ostream&
310operator << (std::ostream& os, const Component& component)
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800311{
312 component.toEscapedString(os);
313 return os;
314}
315
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700316inline
317Component::Component()
318 : Block(Tlv::NameComponent)
319{
320}
321
322inline
323Component::Component(const Block& wire)
324 : Block(wire)
325{
326 if (type() != Tlv::NameComponent)
327 throw Error("Constructing name component from non name component TLV wire block");
328}
329
330inline
331Component::Component(const ConstBufferPtr& buffer)
332 : Block (Tlv::NameComponent, buffer)
333{
334}
335
336inline
337Component::Component(const Buffer& value)
338 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(value)))
339{
340}
341
342inline
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700343Component::Component(const uint8_t* value, size_t valueLen)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700344 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(value, valueLen)))
345{
346}
347
348template<class InputIterator>
349inline
350Component::Component(InputIterator begin, InputIterator end)
351 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(begin, end)))
352{
353}
354
355inline
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700356Component::Component(const char* str)
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700357 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(str, ::strlen(str))))
358{
359}
360
361inline
362Component::Component(const std::string& str)
363 : Block (Tlv::NameComponent, ConstBufferPtr(new Buffer(str.begin(), str.end())))
364{
365}
366
367
368inline Component
369Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
370{
371 std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
372 trim(trimmedString);
373 std::string value = unescape(trimmedString);
374
375 if (value.find_first_not_of(".") == std::string::npos) {
376 // Special case for component of only periods.
377 if (value.size() <= 2)
378 // Zero, one or two periods is illegal. Ignore this component.
379 return Component();
380 else
381 // Remove 3 periods.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700382 return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700383 }
384 else
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700385 return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700386}
387
388
389inline void
390Component::toEscapedString(std::ostream& result) const
391{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700392 const uint8_t* valuePtr = value();
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700393 size_t valueSize = value_size();
394
395 bool gotNonDot = false;
396 for (unsigned i = 0; i < valueSize; ++i) {
397 if (valuePtr[i] != 0x2e) {
398 gotNonDot = true;
399 break;
400 }
401 }
402 if (!gotNonDot) {
403 // Special case for component of zero or more periods. Add 3 periods.
404 result << "...";
405 for (size_t i = 0; i < valueSize; ++i)
406 result << '.';
407 }
408 else {
409 // In case we need to escape, set to upper case hex and save the previous flags.
410 std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
411
412 for (size_t i = 0; i < valueSize; ++i) {
413 uint8_t x = valuePtr[i];
414 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
415 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
416 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
417 x == 0x2e || x == 0x5f)
418 result << x;
419 else {
420 result << '%';
421 if (x < 16)
422 result << '0';
423 result << (unsigned int)x;
424 }
425 }
426
427 // Restore.
428 result.flags(saveFlags);
429 }
430}
431
Alexander Afanasyev4b98e8c2014-03-22 19:10:19 -0700432
433inline Component
434Component::fromNumber(uint64_t number)
435{
436 /// \todo Change to Tlv::NumberComponent
437 return nonNegativeIntegerBlock(Tlv::NameComponent, number);
438}
439
440
441inline uint64_t
442Component::toNumber() const
443{
444 /// \todo Check if Component is of Tlv::NumberComponent type
445 return readNonNegativeInteger(static_cast<const Block&>(*this));
446}
447
448
449inline uint64_t
450Component::toVersion() const
451{
452 return toNumber();
453}
454
455inline uint64_t
456Component::toSegment() const
457{
458 return toNumber();
459}
460
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700461inline int
462Component::compare(const Component& other) const
463{
464 // Imitate ndn_Exclude_compareComponents.
465 if (value_size() < other.value_size())
466 return -1;
467 if (value_size() > other.value_size())
468 return 1;
469
470 if (value_size() == 0)
471 return 0;
472
473 // The components are equal length. Just do a byte compare.
474 return std::memcmp(value(), other.value(), value_size());
475}
476
477
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800478template<bool T>
479inline size_t
480Component::wireEncode(EncodingImpl<T>& block) const
481{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700482 size_t totalLength = 0;
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800483 if (value_size() > 0)
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700484 totalLength += block.prependByteArray (value(), value_size());
485 totalLength += block.prependVarNumber (value_size());
486 totalLength += block.prependVarNumber (Tlv::NameComponent);
487 return totalLength;
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800488}
489
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700490/**
491 * @brief Encode to a wire format
492 */
493inline const Block&
494Component::wireEncode() const
495{
496 if (this->hasWire())
497 return *this;
498
499 EncodingEstimator estimator;
500 size_t estimatedSize = wireEncode(estimator);
501
502 EncodingBuffer buffer(estimatedSize, 0);
503 wireEncode(buffer);
504
505 const_cast<Component&>(*this) = buffer.block();
506 return *this;
507}
508
509/**
510 * @brief Decode from the wire format
511 */
512inline void
513Component::wireDecode(const Block& wire)
514{
515 if (wire.type() != Tlv::NameComponent)
516 throw Error("wireDecode name component from non name component TLV wire block");
517
518 *this = wire;
519}
520
521
Alexander Afanasyev95e8c2f2014-02-06 17:29:30 -0800522} // namespace name
523} // namespace ndn
524
525#endif // NDN_NAME_COMPONENT_HPP