ndn-cxx: NDN C++ Library 0.9.0-33-g832ea91d
Loading...
Searching...
No Matches
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-2024 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 <[email protected]>
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#include <boost/logic/tribool.hpp>
34
35namespace ndn::name {
36
37static Convention g_conventionEncoding = Convention::TYPED;
38static Convention g_conventionDecoding = Convention::EITHER;
39
42{
43 return g_conventionEncoding;
44}
45
46void
48{
49 switch (convention) {
52 g_conventionEncoding = convention;
53 break;
54 default:
55 NDN_THROW(std::invalid_argument("Unknown naming convention"));
56 }
57}
58
61{
62 return g_conventionDecoding;
63}
64
65void
67{
68 g_conventionDecoding = convention;
69}
70
71static bool
72canDecodeMarkerConvention() noexcept
73{
74 return (to_underlying(g_conventionDecoding) & to_underlying(Convention::MARKER)) != 0;
75}
76
77static bool
78canDecodeTypedConvention() noexcept
79{
80 return (to_underlying(g_conventionDecoding) & to_underlying(Convention::TYPED)) != 0;
81}
82
84
86 : Block(type)
87{
88 ensureValid();
89}
90
92 : Block(wire)
93{
94 ensureValid();
95}
96
98 : Block(type, std::move(buffer))
99{
100 ensureValid();
101}
102
103Component::Component(uint32_t type, span<const uint8_t> value)
104 : Block(makeBinaryBlock(type, value))
105{
106 ensureValid();
107}
108
109Component::Component(std::string_view str)
110 : Block(makeStringBlock(tlv::GenericNameComponent, str))
111{
112}
113
114void
115Component::ensureValid() const
116{
118 NDN_THROW(Error("TLV-TYPE " + std::to_string(type()) + " is not a valid NameComponent"));
119 }
120 getComponentTypeTable().get(type()).check(*this);
121}
122
123static Component
124parseUriEscapedValue(uint32_t type, std::string_view input)
125{
126 std::ostringstream oss;
127 unescape(oss, input);
128 std::string value = oss.str();
129 if (value.find_first_not_of('.') == std::string::npos) { // all periods
130 if (value.size() < 3) {
131 NDN_THROW(Component::Error("Illegal URI (name component cannot be . or ..)"));
132 }
133 return Component(type, {reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3});
134 }
135 return Component(type, {reinterpret_cast<const uint8_t*>(value.data()), value.size()});
136}
137
138Component
139Component::fromUri(std::string_view input)
140{
141 size_t equalPos = input.find('=');
142 if (equalPos == std::string_view::npos) {
143 return parseUriEscapedValue(tlv::GenericNameComponent, input);
144 }
145
146 auto typePrefix = input.substr(0, equalPos);
147 auto type = std::strtoul(typePrefix.data(), nullptr, 10);
149 std::to_string(type) == typePrefix) {
150 return parseUriEscapedValue(static_cast<uint32_t>(type), input.substr(equalPos + 1));
151 }
152
153 auto ct = getComponentTypeTable().findByUriPrefix(typePrefix);
154 if (ct == nullptr) {
155 NDN_THROW(Error("Unknown TLV-TYPE '" + std::string(typePrefix) + "' in NameComponent URI"));
156 }
157 return ct->parseAltUriValue(input.substr(equalPos + 1));
158}
159
160static bool
161wantAltUri(UriFormat format)
162{
163 static const auto wantAltEnv = []() -> boost::tribool {
164 const char* env = std::getenv("NDN_NAME_ALT_URI");
165 if (env == nullptr)
166 return boost::indeterminate;
167 else if (env[0] == '0')
168 return false;
169 else if (env[0] == '1')
170 return true;
171 else
172 return boost::indeterminate;
173 }();
174
175 if (format == UriFormat::ENV_OR_CANONICAL) {
176 static const bool wantAlt = boost::indeterminate(wantAltEnv) ? false : bool(wantAltEnv);
177 return wantAlt;
178 }
179 else if (format == UriFormat::ENV_OR_ALTERNATE) {
180 static const bool wantAlt = boost::indeterminate(wantAltEnv) ? true : bool(wantAltEnv);
181 return wantAlt;
182 }
183 else {
184 return format == UriFormat::ALTERNATE;
185 }
186}
187
188void
189Component::toUri(std::ostream& os, UriFormat format) const
190{
191 if (wantAltUri(format)) {
192 getComponentTypeTable().get(type()).writeUri(os, *this);
193 }
194 else {
195 ComponentType().writeUri(os, *this);
196 }
197}
198
199std::string
201{
202 std::ostringstream os;
203 toUri(os, format);
204 return os.str();
205}
206
208
209bool
210Component::isNumber() const noexcept
211{
212 return value_size() == 1 || value_size() == 2 ||
213 value_size() == 4 || value_size() == 8;
214}
215
216bool
217Component::isNumberWithMarker(uint8_t marker) const noexcept
218{
219 return (value_size() == 2 || value_size() == 3 ||
220 value_size() == 5 || value_size() == 9) && value()[0] == marker;
221}
222
223bool
224Component::isSegment() const noexcept
225{
226 return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(SEGMENT_MARKER)) ||
227 (canDecodeTypedConvention() && type() == tlv::SegmentNameComponent && isNumber());
228}
229
230bool
232{
233 return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(SEGMENT_OFFSET_MARKER)) ||
234 (canDecodeTypedConvention() && type() == tlv::ByteOffsetNameComponent && isNumber());
235}
236
237bool
238Component::isVersion() const noexcept
239{
240 return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(VERSION_MARKER)) ||
241 (canDecodeTypedConvention() && type() == tlv::VersionNameComponent && isNumber());
242}
243
244bool
246{
247 return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(TIMESTAMP_MARKER)) ||
248 (canDecodeTypedConvention() && type() == tlv::TimestampNameComponent && isNumber());
249}
250
251bool
253{
254 return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(SEQUENCE_NUMBER_MARKER)) ||
255 (canDecodeTypedConvention() && type() == tlv::SequenceNumNameComponent && isNumber());
256}
257
259
260uint64_t
262{
263 if (!isNumber())
264 NDN_THROW(Error("Name component does not have NonNegativeInteger value"));
265
266 return readNonNegativeInteger(*this);
267}
268
269uint64_t
270Component::toNumberWithMarker(uint8_t marker) const
271{
272 if (!isNumberWithMarker(marker))
273 NDN_THROW(Error("Name component does not have the requested marker "
274 "or the value is not a NonNegativeInteger"));
275
276 auto valueBegin = value_begin() + 1;
277 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
278}
279
280uint64_t
282{
283 if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) {
285 }
286 if (canDecodeTypedConvention() && type() == tlv::SegmentNameComponent) {
287 return toNumber();
288 }
289 NDN_THROW(Error("Not a Segment component"));
290}
291
292uint64_t
294{
295 if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) {
297 }
298 if (canDecodeTypedConvention() && type() == tlv::ByteOffsetNameComponent) {
299 return toNumber();
300 }
301 NDN_THROW(Error("Not a ByteOffset component"));
302}
303
304uint64_t
306{
307 if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) {
309 }
310 if (canDecodeTypedConvention() && type() == tlv::VersionNameComponent) {
311 return toNumber();
312 }
313 NDN_THROW(Error("Not a Version component"));
314}
315
318{
319 uint64_t value = 0;
320 if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) {
322 }
323 else if (canDecodeTypedConvention() && type() == tlv::TimestampNameComponent) {
324 value = toNumber();
325 }
326 else {
327 NDN_THROW(Error("Not a Timestamp component"));
328 }
330}
331
332uint64_t
334{
335 if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) {
337 }
338 if (canDecodeTypedConvention() && type() == tlv::SequenceNumNameComponent) {
339 return toNumber();
340 }
341 NDN_THROW(Error("Not a SequenceNumber component"));
342}
343
345
347Component::fromNumber(uint64_t number, uint32_t type)
348{
349 return Component(makeNonNegativeIntegerBlock(type, number));
350}
351
353Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
354{
355 EncodingEstimator estimator;
356 size_t valueLength = estimator.prependNonNegativeInteger(number);
357 valueLength += estimator.prependBytes({marker});
358 size_t totalLength = valueLength;
359 totalLength += estimator.prependVarNumber(valueLength);
360 totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
361
362 EncodingBuffer encoder(totalLength, 0);
363 encoder.prependNonNegativeInteger(number);
364 encoder.prependBytes({marker});
365 encoder.prependVarNumber(valueLength);
366 encoder.prependVarNumber(tlv::GenericNameComponent);
367
368 return Component(encoder.block());
369}
370
372Component::fromSegment(uint64_t segmentNo)
373{
374 return g_conventionEncoding == Convention::MARKER ?
377}
378
381{
382 return g_conventionEncoding == Convention::MARKER ?
385}
386
388Component::fromVersion(uint64_t version)
389{
390 return g_conventionEncoding == Convention::MARKER ?
393}
394
397{
398 uint64_t value = time::duration_cast<time::microseconds>(timePoint - time::getUnixEpoch()).count();
399 return g_conventionEncoding == Convention::MARKER ?
402}
403
406{
407 return g_conventionEncoding == Convention::MARKER ?
410}
411
413
414bool
419
420bool
425
427
428int
429Component::compare(const Component& other) const
430{
431 if (this->hasWire() && other.hasWire()) {
432 // In the common case where both components have wire encoding,
433 // it's more efficient to simply compare the wire encoding.
434 // This works because lexical order of TLV encoding happens to be
435 // the same as canonical order of the value.
436 return std::memcmp(data(), other.data(), std::min(size(), other.size()));
437 }
438
439 int cmpType = type() - other.type();
440 if (cmpType != 0)
441 return cmpType;
442
443 int cmpSize = value_size() - other.value_size();
444 if (cmpSize != 0)
445 return cmpSize;
446
447 if (empty())
448 return 0;
449
450 return std::memcmp(value(), other.value(), value_size());
451}
452
455{
456 auto [isOverflow, successor] = getComponentTypeTable().get(type()).getSuccessor(*this);
457 if (!isOverflow) {
458 return successor;
459 }
460
461 uint32_t type = this->type() + 1;
462 auto value = getComponentTypeTable().get(type).getMinValue();
463 return {type, value};
464}
465
466template<encoding::Tag TAG>
467size_t
469{
470 size_t totalLength = 0;
471 if (value_size() > 0) {
472 totalLength += encoder.prependBytes(value_bytes());
473 }
474 totalLength += encoder.prependVarNumber(value_size());
475 totalLength += encoder.prependVarNumber(type());
476 return totalLength;
477}
478
480
481const Block&
483{
484 if (this->hasWire())
485 return *this;
486
487 EncodingEstimator estimator;
488 size_t estimatedSize = wireEncode(estimator);
489
490 EncodingBuffer buffer(estimatedSize, 0);
491 wireEncode(buffer);
492
493 const_cast<Component*>(this)->wireDecode(buffer.block());
494 return *this;
495}
496
497void
499{
500 *this = Component(wire);
501 // validity check is done within Component(const Block& wire)
502}
503
504} // namespace ndn::name
Represents a TLV element of the NDN packet format.
Definition block.hpp:45
const uint8_t * data() const
Returns a raw pointer to the beginning of the encoded wire, i.e., the whole TLV.
Definition block.cpp:256
const_iterator value_end() const noexcept
Get end iterator of TLV-VALUE.
Definition block.hpp:338
element_const_iterator find(uint32_t type) const
Find the first sub-element of the specified TLV-TYPE.
Definition block.cpp:425
size_t size() const
Returns the size of the encoded wire, i.e., of the whole TLV.
Definition block.cpp:265
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition block.hpp:205
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition block.hpp:275
span< const uint8_t > value_bytes() const noexcept
Return a read-only view of TLV-VALUE as a contiguous range of bytes.
Definition block.hpp:308
const_iterator value_begin() const noexcept
Get begin iterator of TLV-VALUE.
Definition block.hpp:328
const Block & get(uint32_t type) const
Return the first sub-element of the specified TLV-TYPE.
Definition block.cpp:414
size_t value_size() const noexcept
Return the size of TLV-VALUE, i.e., the TLV-LENGTH.
Definition block.hpp:299
const uint8_t * value() const noexcept
Return a raw pointer to the beginning of TLV-VALUE.
Definition block.cpp:308
constexpr size_t prependNonNegativeInteger(uint64_t n) const noexcept
Prepend n in NonNegativeInteger encoding.
Definition estimator.hpp:99
Represents a name component.
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
static Component fromSegment(uint64_t segmentNo)
Create a segment number component using NDN naming conventions.
bool isTimestamp() const noexcept
Check if the component is a timestamp per NDN naming conventions.
const Block & wireEncode() const
Encode to TLV wire format.
Component getSuccessor() const
Get the successor of this name component.
static Component fromNumber(uint64_t number, uint32_t type=tlv::GenericNameComponent)
Create a component encoded as NonNegativeInteger.
static Component fromTimestamp(const time::system_clock::time_point &timePoint)
Create a timestamp component using NDN naming conventions.
bool isImplicitSha256Digest() const noexcept
Check if the component is an ImplicitSha256DigestComponent.
static Component fromUri(std::string_view input)
Construct a NameComponent from its string representation in NDN URI format.
bool isSegment() const noexcept
Check if the component is a segment number per NDN naming conventions.
uint64_t toNumberWithMarker(uint8_t marker) const
Interpret this name component as a NameComponentWithMarker.
bool isParametersSha256Digest() const noexcept
Check if the component is a ParametersSha256DigestComponent.
static Component fromSequenceNumber(uint64_t seqNo)
Create a sequence number component using NDN naming conventions.
uint64_t toByteOffset() const
Interpret as byte offset component using NDN naming conventions.
static Component fromVersion(uint64_t version)
Create a version component using NDN naming conventions.
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
bool isByteOffset() const noexcept
Check if the component is a byte offset per NDN naming conventions.
Component(uint32_t type=tlv::GenericNameComponent)
Construct a NameComponent of TLV-TYPE type and with empty TLV-VALUE.
static Component fromByteOffset(uint64_t offset)
Create a byte offset component using NDN naming conventions.
bool isNumberWithMarker(uint8_t marker) const noexcept
Check if the component is a NameComponentWithMarker per NDN naming conventions rev1.
static Component fromNumberWithMarker(uint8_t marker, uint64_t number)
Create a component encoded as NameComponentWithMarker.
void toUri(std::ostream &os, UriFormat format=UriFormat::DEFAULT) const
Write *this to the output stream, escaping characters according to the NDN URI format.
void wireDecode(const Block &wire)
Decode from TLV wire format.
bool empty() const noexcept
time::system_clock::time_point toTimestamp() const
Interpret as timestamp component using NDN naming conventions.
bool isVersion() const noexcept
Check if the component is a version per NDN naming conventions.
bool isSequenceNumber() const noexcept
Check if the component is a sequence number per NDN naming conventions.
bool isNumber() const noexcept
Check if the component is a NonNegativeInteger.
int compare(const Component &other) const
Compare this component to other using NDN canonical ordering.
uint64_t toNumber() const
Interpret this name component as a NonNegativeInteger.
uint64_t toVersion() const
Interpret as version component using NDN naming conventions.
::boost::chrono::time_point< system_clock > time_point
Definition time.hpp:205
static constexpr size_t DIGEST_SIZE
Length in bytes of a SHA-256 digest.
Definition sha256.hpp:54
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
#define NDN_THROW(e)
Definition exception.hpp:56
Convention
Identify a style of NDN Naming Conventions.
@ MARKER
Component markers (revision 1)
@ TYPED
Typed name components (revision 3)
void setConventionDecoding(Convention convention)
Set which Naming Conventions style(s) to accept while decoding.
Convention getConventionEncoding() noexcept
Return which Naming Conventions style to use while encoding.
void setConventionEncoding(Convention convention)
Set which Naming Conventions style to use while encoding.
UriFormat
Format used for the URI representation of a name.
@ ALTERNATE
Always prefer the alternate format when available.
@ ENV_OR_ALTERNATE
Same as UriFormat::ALTERNATE, unless NDN_NAME_ALT_URI environment variable is set to '0'.
@ ENV_OR_CANONICAL
Same as UriFormat::CANONICAL, unless NDN_NAME_ALT_URI environment variable is set to '1'.
Convention getConventionDecoding() noexcept
Return which Naming Conventions style(s) to accept while decoding.
const system_clock::time_point & getUnixEpoch()
Return a system_clock::time_point representing the UNIX time epoch, i.e., 00:00:00 UTC on 1 January 1...
Definition time.cpp:105
::boost::chrono::microseconds microseconds
Definition time.hpp:53
@ TimestampNameComponent
Definition tlv.hpp:79
@ GenericNameComponent
Definition tlv.hpp:72
@ ByteOffsetNameComponent
Definition tlv.hpp:77
@ NameComponentMin
Definition tlv.hpp:115
@ VersionNameComponent
Definition tlv.hpp:78
@ SequenceNumNameComponent
Definition tlv.hpp:80
@ NameComponentMax
Definition tlv.hpp:116
@ ParametersSha256DigestComponent
Definition tlv.hpp:74
@ ImplicitSha256DigestComponent
Definition tlv.hpp:73
@ SegmentNameComponent
Definition tlv.hpp:76
constexpr uint64_t readNonNegativeInteger(size_t size, Iterator &begin, Iterator end)
Read a NonNegativeInteger in NDN-TLV encoding.
Definition tlv.hpp:429
constexpr std::underlying_type_t< T > to_underlying(T val) noexcept
Definition backports.hpp:44
std::string unescape(std::string_view str)
Decode a percent-encoded string.
std::shared_ptr< const Buffer > ConstBufferPtr
Definition buffer.hpp:140
STL namespace.