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 <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 
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 
35 namespace ndn {
36 
37 // ---- constructors, encoding, decoding ----
38 
39 Name::Name() = default;
40 
41 Name::Name(const Block& wire)
42 {
43  wireDecode(wire);
44 }
45 
46 Name::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 
90 template<encoding::Tag TAG>
91 size_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 
106 const 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 
124 void
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 
134 Name
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 
145 const name::Component&
146 Name::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 
160 Name::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 
180 Name&
181 Name::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 
192 Name&
193 Name::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 
204 Name&
205 Name::appendVersion(const std::optional<uint64_t>& version)
206 {
207  return append(Component::fromVersion(version.value_or(time::toUnixTimestamp(time::system_clock::now()).count())));
208 }
209 
210 Name&
211 Name::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 
216 Name&
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 
230 static 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 
237 Name&
239 {
240  static const Component placeholder(tlv::ParametersSha256DigestComponent, SHA256_OF_EMPTY_STRING);
241  return append(placeholder);
242 }
243 
244 void
245 Name::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 
255 void
257 {
258  m_wire = Block(tlv::Name);
259 }
260 
261 // ---- algorithms ----
262 
263 Name
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 
274 bool
275 Name::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 
290 bool
291 Name::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 
304 int
305 Name::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 
323 void
324 Name::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 
337 std::string
339 {
340  std::ostringstream os;
341  toUri(os, format);
342  return os.str();
343 }
344 
345 std::istream&
346 operator>>(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 
357 namespace std {
358 
359 size_t
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
element_iterator erase(element_const_iterator position)
Erase a sub-element.
Definition: block.cpp:442
const element_container & elements() const noexcept
Get container of sub-elements.
Definition: block.hpp:424
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
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 & 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 & append(const Component &component)
Append a name component.
Definition: name.hpp:308
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
const Component & get(ssize_t i) const noexcept
Returns an immutable reference to the component at the specified index.
Definition: name.hpp:192
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
EncodingImpl< EstimatorTag > EncodingEstimator
EncodingImpl< EncoderTag > EncodingBuffer
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:30
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
size_t operator()(const ndn::Name &name) const
Definition: name.cpp:360