name-component.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2019 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  *
21  * @author Jeff Thompson <jefft0@remap.ucla.edu>
22  * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
23  * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
24  */
25 
27 #include "ndn-cxx/impl/name-component-types.hpp"
28 
29 #include <cstdlib>
30 #include <cstring>
31 #include <sstream>
32 
33 namespace ndn {
34 namespace name {
35 
36 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
37 BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
38 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Component>));
39 BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
40 static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
41  "name::Component::Error must inherit from tlv::Error");
42 
45 
48 {
49  return g_conventionEncoding;
50 }
51 
52 void
54 {
55  switch (convention) {
56  case Convention::MARKER:
57  case Convention::TYPED:
58  g_conventionEncoding = convention;
59  break;
60  default:
61  NDN_THROW(std::invalid_argument("Unknown naming convention"));
62  }
63 }
64 
67 {
68  return g_conventionDecoding;
69 }
70 
71 void
73 {
74  g_conventionDecoding = convention;
75 }
76 
77 static bool
79 {
80  return (static_cast<int>(g_conventionDecoding) & static_cast<int>(Convention::MARKER)) != 0;
81 }
82 
83 static bool
85 {
86  return (static_cast<int>(g_conventionDecoding) & static_cast<int>(Convention::TYPED)) != 0;
87 }
88 
89 void
90 Component::ensureValid() const
91 {
93  NDN_THROW(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
94  }
95  detail::getComponentTypeTable().get(type()).check(*this);
96 }
97 
99  : Block(type)
100 {
101  ensureValid();
102 }
103 
105  : Block(wire)
106 {
107  ensureValid();
108 }
109 
111  : Block(type, std::move(buffer))
112 {
113  ensureValid();
114 }
115 
116 Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
117  : Block(makeBinaryBlock(type, value, valueLen))
118 {
119  ensureValid();
120 }
121 
122 Component::Component(const char* str)
123  : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
124 {
125 }
126 
127 Component::Component(const std::string& str)
129 {
130 }
131 
132 static Component
133 parseUriEscapedValue(uint32_t type, const char* input, size_t len)
134 {
135  std::ostringstream oss;
136  unescape(oss, input, len);
137  std::string value = oss.str();
138  if (value.find_first_not_of('.') == std::string::npos) { // all periods
139  if (value.size() < 3) {
140  NDN_THROW(Component::Error("Illegal URI (name component cannot be . or ..)"));
141  }
142  return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
143  }
144  return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size());
145 }
146 
147 Component
148 Component::fromEscapedString(const std::string& input)
149 {
150  size_t equalPos = input.find('=');
151  if (equalPos == std::string::npos) {
152  return parseUriEscapedValue(tlv::GenericNameComponent, input.data(), input.size());
153  }
154 
155  auto typePrefix = input.substr(0, equalPos);
156  auto type = std::strtoul(typePrefix.data(), nullptr, 10);
158  to_string(type) == typePrefix) {
159  size_t valuePos = equalPos + 1;
160  return parseUriEscapedValue(static_cast<uint32_t>(type),
161  input.data() + valuePos, input.size() - valuePos);
162  }
163 
164  auto ct = detail::getComponentTypeTable().findByUriPrefix(typePrefix);
165  if (ct == nullptr) {
166  NDN_THROW(Error("Incorrect TLV-TYPE '" + typePrefix + "' in NameComponent URI"));
167  }
168  return ct->parseAltUriValue(input.substr(equalPos + 1));
169 }
170 
171 void
172 Component::toUri(std::ostream& os) const
173 {
174  detail::getComponentTypeTable().get(type()).writeUri(os, *this);
175 }
176 
177 std::string
179 {
180  std::ostringstream os;
181  toUri(os);
182  return os.str();
183 }
184 
186 
187 bool
189 {
190  return (value_size() == 1 || value_size() == 2 ||
191  value_size() == 4 || value_size() == 8);
192 }
193 
194 bool
195 Component::isNumberWithMarker(uint8_t marker) const
196 {
197  return (!empty() && value()[0] == marker &&
198  (value_size() == 2 || value_size() == 3 ||
199  value_size() == 5 || value_size() == 9));
200 }
201 
202 bool
204 {
207 }
208 
209 bool
211 {
214 }
215 
216 bool
218 {
221 }
222 
223 bool
225 {
228 }
229 
230 bool
232 {
235 }
236 
238 
239 uint64_t
241 {
242  if (!isNumber())
243  NDN_THROW(Error("Name component does not have nonNegativeInteger value"));
244 
245  return readNonNegativeInteger(*this);
246 }
247 
248 uint64_t
249 Component::toNumberWithMarker(uint8_t marker) const
250 {
251  if (!isNumberWithMarker(marker))
252  NDN_THROW(Error("Name component does not have the requested marker "
253  "or the value is not a nonNegativeInteger"));
254 
255  Buffer::const_iterator valueBegin = value_begin() + 1;
256  return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
257 }
258 
259 uint64_t
261 {
264  }
266  return toNumber();
267  }
268  NDN_THROW(Error("Not a Version component"));
269 }
270 
271 uint64_t
273 {
276  }
278  return toNumber();
279  }
280  NDN_THROW(Error("Not a Segment component"));
281 }
282 
283 uint64_t
285 {
288  }
290  return toNumber();
291  }
292  NDN_THROW(Error("Not a ByteOffset component"));
293 }
294 
297 {
298  uint64_t value = 0;
301  }
303  value = toNumber();
304  }
305  else {
306  NDN_THROW(Error("Not a Timestamp component"));
307  }
308  return time::getUnixEpoch() + time::microseconds(value);
309 }
310 
311 uint64_t
313 {
316  }
318  return toNumber();
319  }
320  NDN_THROW(Error("Not a SequenceNumber component"));
321 }
322 
324 
325 Component
326 Component::fromNumber(uint64_t number, uint32_t type)
327 {
328  return makeNonNegativeIntegerBlock(type, number);
329 }
330 
331 Component
332 Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
333 {
334  EncodingEstimator estimator;
335 
336  size_t valueLength = estimator.prependNonNegativeInteger(number);
337  valueLength += estimator.prependByteArray(&marker, 1);
338  size_t totalLength = valueLength;
339  totalLength += estimator.prependVarNumber(valueLength);
340  totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
341 
342  EncodingBuffer encoder(totalLength, 0);
343  encoder.prependNonNegativeInteger(number);
344  encoder.prependByteArray(&marker, 1);
345  encoder.prependVarNumber(valueLength);
346  encoder.prependVarNumber(tlv::GenericNameComponent);
347 
348  return encoder.block();
349 }
350 
351 Component
352 Component::fromVersion(uint64_t version)
353 {
354  return g_conventionEncoding == Convention::MARKER ?
357 }
358 
359 Component
360 Component::fromSegment(uint64_t segmentNo)
361 {
362  return g_conventionEncoding == Convention::MARKER ?
365 }
366 
367 Component
369 {
370  return g_conventionEncoding == Convention::MARKER ?
373 }
374 
375 Component
377 {
378  uint64_t value = time::duration_cast<time::microseconds>(timePoint - time::getUnixEpoch()).count();
379  return g_conventionEncoding == Convention::MARKER ?
382 }
383 
384 Component
386 {
387  return g_conventionEncoding == Convention::MARKER ?
390 }
391 
393 
394 bool
396 {
397  return type() == tlv::GenericNameComponent;
398 }
399 
400 bool
402 {
403  return detail::getComponentType1().match(*this);
404 }
405 
406 Component
408 {
409  return detail::getComponentType1().create(digest);
410 }
411 
412 Component
413 Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
414 {
415  return detail::getComponentType1().create(digest, digestSize);
416 }
417 
418 bool
420 {
421  return detail::getComponentType2().match(*this);
422 }
423 
424 Component
426 {
427  return detail::getComponentType2().create(digest);
428 }
429 
430 Component
431 Component::fromParametersSha256Digest(const uint8_t* digest, size_t digestSize)
432 {
433  return detail::getComponentType2().create(digest, digestSize);
434 }
435 
437 
438 bool
439 Component::equals(const Component& other) const
440 {
441  return type() == other.type() &&
442  value_size() == other.value_size() &&
443  (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug
444  std::equal(value_begin(), value_end(), other.value_begin()));
445 }
446 
447 int
448 Component::compare(const Component& other) const
449 {
450  if (this->hasWire() && other.hasWire()) {
451  // In the common case where both components have wire encoding,
452  // it's more efficient to simply compare the wire encoding.
453  // This works because lexical order of TLV encoding happens to be
454  // the same as canonical order of the value.
455  return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
456  }
457 
458  int cmpType = type() - other.type();
459  if (cmpType != 0)
460  return cmpType;
461 
462  int cmpSize = value_size() - other.value_size();
463  if (cmpSize != 0)
464  return cmpSize;
465 
466  if (empty())
467  return 0;
468 
469  return std::memcmp(value(), other.value(), value_size());
470 }
471 
472 Component
474 {
475  bool isOverflow = false;
476  Component successor;
477  std::tie(isOverflow, successor) =
478  detail::getComponentTypeTable().get(type()).getSuccessor(*this);
479  if (!isOverflow) {
480  return successor;
481  }
482 
483  uint32_t type = this->type() + 1;
484  const std::vector<uint8_t>& value = detail::getComponentTypeTable().get(type).getMinValue();
485  return Component(type, value.data(), value.size());
486 }
487 
488 template<encoding::Tag TAG>
489 size_t
490 Component::wireEncode(EncodingImpl<TAG>& encoder) const
491 {
492  size_t totalLength = 0;
493  if (value_size() > 0)
494  totalLength += encoder.prependByteArray(value(), value_size());
495  totalLength += encoder.prependVarNumber(value_size());
496  totalLength += encoder.prependVarNumber(type());
497  return totalLength;
498 }
499 
501 
502 const Block&
504 {
505  if (this->hasWire())
506  return *this;
507 
508  EncodingEstimator estimator;
509  size_t estimatedSize = wireEncode(estimator);
510 
511  EncodingBuffer buffer(estimatedSize, 0);
512  wireEncode(buffer);
513 
514  const_cast<Component&>(*this) = buffer.block();
515  return *this;
516 }
517 
518 void
520 {
521  *this = wire;
522  // validity check is done within Component(const Block& wire)
523 }
524 
525 } // namespace name
526 } // namespace ndn
static Component fromParametersSha256Digest(ConstBufferPtr digest)
Create ParametersSha256DigestComponent component.
void setConventionDecoding(Convention convention)
Set which Naming Conventions style(s) to accept while decoding.
static Component fromSequenceNumber(uint64_t seqNo)
Create sequence number component using NDN naming conventions.
bool isGeneric() const
Check if the component is GenericComponent.
Definition: data.cpp:26
static Convention g_conventionEncoding
bool isTimestamp() const
Check if the component is a timestamp per NDN naming conventions.
static Component fromNumberWithMarker(uint8_t marker, uint64_t number)
Create a component encoded as NameComponentWithMarker.
int compare(const Component &other) const
Compare this to the other Component using NDN canonical ordering.
const Block & wireEncode() const
Encode to a wire format.
std::string toUri() const
Convert *this by escaping characters according to the NDN URI Scheme.
static bool canDecodeMarkerConvention()
element_const_iterator find(uint32_t type) const
Find the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:425
Component(uint32_t type=tlv::GenericNameComponent)
Construct a NameComponent of TLV-TYPE type, using empty TLV-VALUE.
time::system_clock::TimePoint toTimestamp() const
Interpret as timestamp component using NDN naming conventions.
bool isNumberWithMarker(uint8_t marker) const
Check if the component is a NameComponentWithMarker per NDN naming conventions rev1.
bool isSequenceNumber() const
Check if the component is a sequence number per NDN naming conventions.
static Component fromTimestamp(const time::system_clock::TimePoint &timePoint)
Create sequence number component using NDN naming conventions.
STL namespace.
size_t value_size() const noexcept
Return the size of TLV-VALUE, aka TLV-LENGTH.
Definition: block.cpp:307
uint64_t toByteOffset() const
Interpret as byte offset component using NDN naming conventions.
static Convention g_conventionDecoding
void setConventionEncoding(Convention convention)
Set which Naming Conventions style to use while encoding.
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
uint64_t readNonNegativeInteger(size_t size, Iterator &begin, Iterator end)
Read nonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:487
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:230
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block containing a non-negative integer.
Buffer::const_iterator value_begin() const
Get begin iterator of TLV-VALUE.
Definition: block.hpp:296
Buffer::const_iterator value_end() const
Get end iterator of TLV-VALUE.
Definition: block.hpp:305
uint64_t readNonNegativeInteger(const Block &block)
Read a non-negative integer from a TLV element.
#define NDN_THROW(e)
Definition: exception.hpp:61
typed name components (revision 2)
uint64_t toNumberWithMarker(uint8_t marker) const
Interpret this name component as NameComponentWithMarker.
size_t size() const
Return the size of the encoded wire, i.e.
Definition: block.cpp:289
static Component fromSegment(uint64_t segmentNo)
Create segment number component using NDN naming conventions.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:60
Convention getConventionDecoding()
Return which Naming Conventions style(s) to accept while decoding.
bool isSegment() const
Check if the component is a segment number per NDN naming conventions.
bool isVersion() const
Check if the component is a version per NDN naming conventions.
uint64_t toVersion() const
Interpret as version component using NDN naming conventions.
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
static Component fromByteOffset(uint64_t offset)
Create byte offset component using NDN naming conventions.
static Component fromEscapedString(const char *input, size_t beginOffset, size_t endOffset)
Decode NameComponent from a URI component.
Block makeBinaryBlock(uint32_t type, const uint8_t *value, size_t length)
Create a TLV block copying TLV-VALUE from raw buffer.
static bool canDecodeTypedConvention()
Block makeStringBlock(uint32_t type, const std::string &value)
Create a TLV block containing a string.
const Block & get(uint32_t type) const
Return the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:413
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
std::string unescape(const std::string &str)
Decode a percent-encoded string.
uint32_t type() const
Return the TLV-TYPE of the Block.
Definition: block.hpp:274
Component getSuccessor() const
Get the successor of this name component.
time_point TimePoint
Definition: time.hpp:195
static Component parseUriEscapedValue(uint32_t type, const char *input, size_t len)
const uint8_t * value() const noexcept
Return a raw pointer to the beginning of TLV-VALUE.
Definition: block.cpp:301
Represents a name component.
void wireDecode(const Block &wire)
Decode from the wire format.
bool isNumber() const
Check if the component is a nonNegativeInteger.
static Component fromNumber(uint64_t number, uint32_t type=tlv::GenericNameComponent)
Create a component encoded as nonNegativeInteger.
const uint8_t * wire() const
Return a raw pointer to the beginning of the encoded wire.
Definition: block.cpp:280
component markers (revision 1)
Convention getConventionEncoding()
Return which Naming Conventions style to use while encoding.
static Component fromVersion(uint64_t version)
Create version component using NDN naming conventions.
std::string to_string(const V &v)
Definition: backports.hpp:67
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
Convention
Identify a style of NDN Naming Conventions.
bool equals(const Component &other) const
Check if this is the same component as other.
static Component fromImplicitSha256Digest(ConstBufferPtr digest)
Create ImplicitSha256DigestComponent component.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:44
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
a concept check for TLV abstraction with .wireDecode method and constructible from Block ...
Definition: concepts.hpp:80
bool isParametersSha256Digest() const
Check if the component is ParametersSha256DigestComponent.
EncodingImpl< EncoderTag > EncodingBuffer
const system_clock::TimePoint & getUnixEpoch()
Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) ...
Definition: time.cpp:106
size_t prependNonNegativeInteger(uint64_t integer) const noexcept
Prepend non-negative integer integer of NDN TLV encoding.
Definition: estimator.cpp:51
EncodingImpl< EstimatorTag > EncodingEstimator
bool isImplicitSha256Digest() const
Check if the component is ImplicitSha256DigestComponent.
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:126
bool isByteOffset() const
Check if the component is a byte offset per NDN naming conventions.