ndn-cxx: NDN C++ Library 0.9.0-33-g832ea91d
Loading...
Searching...
No Matches
name.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
26#include "ndn-cxx/name.hpp"
29#include "ndn-cxx/util/time.hpp"
30
31#include <sstream>
32#include <boost/functional/hash.hpp>
33#include <boost/range/adaptor/reversed.hpp>
34
35namespace ndn {
36
37// ---- constructors, encoding, decoding ----
38
39Name::Name() = default;
40
41Name::Name(const Block& wire)
42{
43 wireDecode(wire);
44}
45
46Name::Name(std::string_view uri)
47{
48 if (uri.empty())
49 return;
50
51 if (size_t iColon = uri.find(':'); iColon != std::string_view::npos) {
52 // Make sure the colon came before a '/', if any.
53 size_t iFirstSlash = uri.find('/');
54 if (iFirstSlash == std::string_view::npos || iColon < iFirstSlash) {
55 // Strip the leading protocol such as "ndn:".
56 uri.remove_prefix(iColon + 1);
57 }
58 }
59
60 // Trim the leading slash and possibly the authority.
61 if (uri.size() >= 1 && uri[0] == '/') {
62 if (uri.size() >= 2 && uri[1] == '/') {
63 // Strip the authority following "//".
64 size_t iAfterAuthority = uri.find('/', 2);
65 if (iAfterAuthority == std::string_view::npos) {
66 // Unusual case: there was only an authority.
67 return;
68 }
69 else {
70 uri.remove_prefix(iAfterAuthority + 1);
71 }
72 }
73 else {
74 uri.remove_prefix(1);
75 }
76 }
77
78 // Unescape the components.
79 while (!uri.empty()) {
80 auto component = uri.substr(0, uri.find('/'));
81 append(Component::fromUri(component));
82 if (component.size() + 1 >= uri.size()) {
83 // We reached the end of the string.
84 return;
85 }
86 uri.remove_prefix(component.size() + 1);
87 }
88}
89
90template<encoding::Tag TAG>
91size_t
93{
94 size_t totalLength = 0;
95 for (const Component& comp : *this | boost::adaptors::reversed) {
96 totalLength += comp.wireEncode(encoder);
97 }
98
99 totalLength += encoder.prependVarNumber(totalLength);
100 totalLength += encoder.prependVarNumber(tlv::Name);
101 return totalLength;
102}
103
105
106const Block&
108{
109 if (m_wire.hasWire())
110 return m_wire;
111
112 EncodingEstimator estimator;
113 size_t estimatedSize = wireEncode(estimator);
114
115 EncodingBuffer buffer(estimatedSize, 0);
116 wireEncode(buffer);
117
118 m_wire = buffer.block();
119 m_wire.parse();
120
121 return m_wire;
122}
123
124void
126{
127 if (wire.type() != tlv::Name)
128 NDN_THROW(tlv::Error("Name", wire.type()));
129
130 m_wire = wire;
131 m_wire.parse();
132}
133
134Name
136{
137 Name copiedName(*this);
138 copiedName.m_wire.resetWire();
139 copiedName.wireEncode(); // "compress" the underlying buffer
140 return copiedName;
141}
142
143// ---- accessors ----
144
145const name::Component&
146Name::at(ssize_t i) const
147{
148 auto ssize = static_cast<ssize_t>(size());
149 if (i < -ssize || i >= ssize) {
150 NDN_THROW(Error("Component at offset " + to_string(i) + " does not exist (out of bounds)"));
151 }
152
153 if (i < 0) {
154 i += ssize;
155 }
156 return static_cast<const Component&>(m_wire.elements()[static_cast<size_t>(i)]);
157}
158
160Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
161{
162 PartialName result;
163
164 if (iStartComponent < 0)
165 iStartComponent += static_cast<ssize_t>(size());
166 size_t iStart = iStartComponent < 0 ? 0 : static_cast<size_t>(iStartComponent);
167
168 size_t iEnd = size();
169 if (nComponents != npos)
170 iEnd = std::min(size(), iStart + nComponents);
171
172 for (size_t i = iStart; i < iEnd; ++i)
173 result.append(at(i));
174
175 return result;
176}
177
178// ---- modifiers ----
179
180Name&
181Name::set(ssize_t i, const Component& component)
182{
183 if (i < 0) {
184 i += static_cast<ssize_t>(size());
185 }
186
187 const_cast<Block::element_container&>(m_wire.elements())[i] = component;
188 m_wire.resetWire();
189 return *this;
190}
191
192Name&
193Name::set(ssize_t i, Component&& component)
194{
195 if (i < 0) {
196 i += static_cast<ssize_t>(size());
197 }
198
199 const_cast<Block::element_container&>(m_wire.elements())[i] = std::move(component);
200 m_wire.resetWire();
201 return *this;
202}
203
204Name&
205Name::appendVersion(const std::optional<uint64_t>& version)
206{
208}
209
210Name&
211Name::appendTimestamp(const std::optional<time::system_clock::time_point>& timestamp)
212{
213 return append(Component::fromTimestamp(timestamp.value_or(time::system_clock::now())));
214}
215
216Name&
218{
219 if (&name == this) {
220 // Copying from this name, so need to make a copy first.
221 return append(PartialName(name));
222 }
223
224 for (const auto& c : name) {
225 append(c);
226 }
227 return *this;
228}
229
230static constexpr uint8_t SHA256_OF_EMPTY_STRING[] = {
231 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
232 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
233 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
234 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
235};
236
237Name&
239{
240 static const Component placeholder(tlv::ParametersSha256DigestComponent, SHA256_OF_EMPTY_STRING);
241 return append(placeholder);
242}
243
244void
245Name::erase(ssize_t i)
246{
247 if (i >= 0) {
248 m_wire.erase(std::next(m_wire.elements_begin(), i));
249 }
250 else {
251 m_wire.erase(std::prev(m_wire.elements_end(), -i));
252 }
253}
254
255void
257{
258 m_wire = Block(tlv::Name);
259}
260
261// ---- algorithms ----
262
263Name
265{
266 if (empty()) {
267 static const Name n("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
268 return n;
269 }
270
271 return getPrefix(-1).append(get(-1).getSuccessor());
272}
273
274bool
275Name::isPrefixOf(const Name& other) const noexcept
276{
277 // This name is longer than the name we are checking against.
278 if (size() > other.size())
279 return false;
280
281 // Check if at least one of given components doesn't match.
282 for (size_t i = 0; i < size(); ++i) {
283 if (get(i) != other.get(i))
284 return false;
285 }
286
287 return true;
288}
289
290bool
291Name::equals(const Name& other) const noexcept
292{
293 if (size() != other.size())
294 return false;
295
296 for (size_t i = 0; i < size(); ++i) {
297 if (get(i) != other.get(i))
298 return false;
299 }
300
301 return true;
302}
303
304int
305Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
306{
307 count1 = std::min(count1, this->size() - pos1);
308 count2 = std::min(count2, other.size() - pos2);
309 size_t count = std::min(count1, count2);
310
311 for (size_t i = 0; i < count; ++i) {
312 int comp = get(pos1 + i).compare(other.get(pos2 + i));
313 if (comp != 0) { // i-th component differs
314 return comp;
315 }
316 }
317 // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
318 return count1 - count2;
319}
320
321// ---- URI representation ----
322
323void
324Name::toUri(std::ostream& os, name::UriFormat format) const
325{
326 if (empty()) {
327 os << "/";
328 return;
329 }
330
331 for (const auto& component : *this) {
332 os << "/";
333 component.toUri(os, format);
334 }
335}
336
337std::string
339{
340 std::ostringstream os;
341 toUri(os, format);
342 return os.str();
343}
344
345std::istream&
346operator>>(std::istream& is, Name& name)
347{
348 std::string inputString;
349 is >> inputString;
350 name = Name(inputString);
351
352 return is;
353}
354
355} // namespace ndn
356
357namespace std {
358
359size_t
360hash<ndn::Name>::operator()(const ndn::Name& name) const
361{
362 return boost::hash_range(name.wireEncode().begin(), name.wireEncode().end());
363}
364
365} // namespace std
Represents a TLV element of the NDN packet format.
Definition block.hpp:45
element_const_iterator elements_begin() const noexcept
Equivalent to elements().begin().
Definition block.hpp:433
const element_container & elements() const noexcept
Get container of sub-elements.
Definition block.hpp:424
element_iterator erase(element_const_iterator position)
Erase a sub-element.
Definition block.cpp:442
element_const_iterator elements_end() const noexcept
Equivalent to elements().end().
Definition block.hpp:442
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition block.hpp:205
void resetWire() noexcept
Reset wire buffer but keep TLV-TYPE and sub-elements (if any).
Definition block.cpp:299
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition block.hpp:275
std::vector< Block > element_container
Definition block.hpp:49
void parse() const
Parse TLV-VALUE into sub-elements.
Definition block.cpp:326
Represents an absolute name.
Definition name.hpp:45
bool equals(const Name &other) const noexcept
Check if this name equals another name.
Definition name.cpp:291
const Component & get(ssize_t i) const noexcept
Returns an immutable reference to the component at the specified index.
Definition name.hpp:192
Name & set(ssize_t i, const Component &component)
Replace the component at the specified index.
Definition name.cpp:181
Name & appendTimestamp(const std::optional< time::system_clock::time_point > &timestamp=std::nullopt)
Append a timestamp component.
Definition name.cpp:211
Name getSuccessor() const
Get the successor of a name.
Definition name.cpp:264
PartialName getPrefix(ssize_t nComponents) const
Returns a prefix of the name.
Definition name.hpp:241
int compare(const Name &other) const
Compare this to the other Name using NDN canonical ordering.
Definition name.hpp:634
Name & append(const Component &component)
Append a name component.
Definition name.hpp:308
Name & appendParametersSha256DigestPlaceholder()
Append a placeholder for a ParametersSha256Digest component.
Definition name.cpp:238
Name & appendVersion(const std::optional< uint64_t > &version=std::nullopt)
Append a version component.
Definition name.cpp:205
size_t size() const noexcept
Returns the number of components.
Definition name.hpp:180
static constexpr size_t npos
Indicates "until the end" in getSubName() and compare().
Definition name.hpp:680
bool empty() const noexcept
Checks if the name is empty, i.e., has no components.
Definition name.hpp:171
void clear()
Remove all components.
Definition name.cpp:256
Name()
Create an empty name.
const Component & at(ssize_t i) const
Returns an immutable reference to the component at the specified index, with bounds checking.
Definition name.cpp:146
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Prepend wire encoding to encoder.
Definition name.cpp:92
Name deepCopy() const
Make a deep copy of the name, reallocating the underlying memory buffer.
Definition name.cpp:135
const Block & wireEncode() const
Perform wire encoding, or return existing (cached) wire encoding.
Definition name.cpp:107
Component::Error Error
Definition name.hpp:48
PartialName getSubName(ssize_t iStartComponent, size_t nComponents=npos) const
Extracts some components as a sub-name (PartialName).
Definition name.cpp:160
void erase(ssize_t i)
Erase the component at the specified index.
Definition name.cpp:245
void toUri(std::ostream &os, name::UriFormat format=name::UriFormat::DEFAULT) const
Write URI representation of the name to the output stream.
Definition name.cpp:324
bool isPrefixOf(const Name &other) const noexcept
Check if this name is a prefix of another name.
Definition name.cpp:275
void wireDecode(const Block &wire)
Decode name from wire encoding.
Definition name.cpp:125
Represents a name component.
static Component fromTimestamp(const time::system_clock::time_point &timePoint)
Create a timestamp component using NDN naming conventions.
static Component fromUri(std::string_view input)
Construct a NameComponent from its string representation in NDN URI format.
static Component fromVersion(uint64_t version)
Create a version component using NDN naming conventions.
int compare(const Component &other) const
Compare this component to other using NDN canonical ordering.
static time_point now() noexcept
Definition time.cpp:45
Represents an error in TLV encoding or decoding.
Definition tlv.hpp:54
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
#define NDN_THROW(e)
Definition exception.hpp:56
UriFormat
Format used for the URI representation of a name.
constexpr Duration toUnixTimestamp(const system_clock::time_point &tp)
Convert system_clock::time_point to UNIX timestamp.
Definition time.hpp:265
@ Name
Definition tlv.hpp:71
@ ParametersSha256DigestComponent
Definition tlv.hpp:74
Definition data.cpp:25
Name PartialName
Represents an arbitrary sequence of name components.
Definition name.hpp:38
std::istream & operator>>(std::istream &is, Name &name)
Parse URI from stream as Name.
Definition name.cpp:346
STL namespace.