ndn-embeds 0.1.0
Lightweight NDN protocol stack for embedded systems
Loading...
Searching...
No Matches
name.cpp
1#include "ndn/name.hpp"
2#include "ndn/tlv.hpp"
3#include <cstring>
4
5namespace ndn {
6
7namespace {
8
9// Hex decode from URI
10int hexValue(char c) {
11 if (c >= '0' && c <= '9') {
12 return c - '0';
13 }
14 if (c >= 'a' && c <= 'f') {
15 return c - 'a' + 10;
16 }
17 if (c >= 'A' && c <= 'F') {
18 return c - 'A' + 10;
19 }
20 return -1;
21}
22
23} // namespace
24
25Result<Name> Name::fromUri(std::string_view uri) {
26 Name name;
27
28 // Skip leading "ndn:" prefix (optional)
29 if (uri.starts_with("ndn:")) {
30 uri = uri.substr(4);
31 }
32
33 // Empty name
34 if (uri.empty() || uri == "/") {
35 return {.value = name, .error = Error::Success};
36 }
37
38 // Skip leading "/"
39 if (uri[0] == '/') {
40 uri = uri.substr(1);
41 }
42
43 // Parse components
44 size_t start = 0;
45 while (start < uri.size()) {
46 // Find the next "/"
47 size_t end = uri.find('/', start);
48 if (end == std::string_view::npos) {
49 end = uri.size();
50 }
51
52 const std::string_view compStr = uri.substr(start, end - start);
53
54 if (!compStr.empty()) {
55 // URL decode processing
56 uint8_t compBuf[NAME_MAX_LENGTH];
57 size_t compLen = 0;
58
59 for (size_t i = 0; i < compStr.size() && compLen < NAME_MAX_LENGTH; ++i) {
60 if (compStr[i] == '%' && i + 2 < compStr.size()) {
61 const int hi = hexValue(compStr[i + 1]);
62 const int lo = hexValue(compStr[i + 2]);
63 if (hi >= 0 && lo >= 0) {
64 compBuf[compLen++] = static_cast<uint8_t>((hi << 4) | lo);
65 i += 2;
66 continue;
67 }
68 }
69 compBuf[compLen++] = static_cast<uint8_t>(compStr[i]);
70 }
71
72 const Error err = name.appendComponentInternal(compBuf, compLen);
73 if (err != Error::Success) {
74 return {.value = Name{}, .error = err};
75 }
76 }
77
78 start = end + 1;
79 }
80
81 return {.value = name, .error = Error::Success};
82}
83
84Result<Name> Name::fromWire(const uint8_t* buf, size_t len, size_t* bytesRead) {
85 Name name;
86 TlvDecoder decoder(buf, len);
87
88 // Read Name TLV header
89 auto headerResult = decoder.readTlvHeader();
90 if (!headerResult.ok()) {
91 return {.value = Name{}, .error = headerResult.error};
92 }
93
94 if (headerResult.value.type != tlv::Name) {
95 return {.value = Name{}, .error = Error::DecodeFailed};
96 }
97
98 const size_t nameValueLen = headerResult.value.length;
99 if (decoder.remaining() < nameValueLen) {
100 return {.value = Name{}, .error = Error::DecodeFailed};
101 }
102
103 // Start position of Name value
104 const size_t nameValueStart = decoder.position();
105
106 // Parse components
107 while (decoder.position() < nameValueStart + nameValueLen) {
108 auto compHeader = decoder.readTlvHeader();
109 if (!compHeader.ok()) {
110 return {.value = Name{}, .error = compHeader.error};
111 }
112
113 // Only GenericNameComponent (0x08) is supported
114 if (compHeader.value.type != tlv::GenericNameComponent) {
115 // Skip other types
116 if (decoder.skip(compHeader.value.length) != Error::Success) {
117 return {.value = Name{}, .error = Error::DecodeFailed};
118 }
119 continue;
120 }
121
122 if (decoder.remaining() < compHeader.value.length) {
123 return {.value = Name{}, .error = Error::DecodeFailed};
124 }
125
126 const Error err = name.appendComponentInternal(decoder.current(), compHeader.value.length);
127 if (err != Error::Success) {
128 return {.value = Name{}, .error = err};
129 }
130
131 decoder.skip(compHeader.value.length);
132 }
133
134 if (bytesRead != nullptr) {
135 *bytesRead = decoder.position();
136 }
137
138 return {.value = name, .error = Error::Success};
139}
140
141size_t Name::toUri(char* buf, size_t bufSize) const {
142 if (bufSize == 0) {
143 return 0;
144 }
145
146 size_t written = 0;
147
148 if (numComponents_ == 0) {
149 if (bufSize >= 2) {
150 buf[0] = '/';
151 buf[1] = '\0';
152 return 1;
153 }
154 buf[0] = '\0';
155 return 0;
156 }
157
158 for (size_t i = 0; i < numComponents_; ++i) {
159 // Write "/"
160 if (written < bufSize - 1) {
161 buf[written++] = '/';
162 }
163
164 const NameComponent comp = component(i);
165
166 // Write component value
167 for (size_t j = 0; j < comp.size && written < bufSize - 1; ++j) {
168 const uint8_t c = comp.value[j];
169 // Printable characters as-is, others are percent-encoded
170 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
171 c == '-' || c == '.' || c == '_' || c == '~') {
172 buf[written++] = static_cast<char>(c);
173 } else if (written + 3 < bufSize) {
174 static const char hex[] = "0123456789ABCDEF";
175 buf[written++] = '%';
176 buf[written++] = hex[c >> 4];
177 buf[written++] = hex[c & 0x0F];
178 }
179 }
180 }
181
182 buf[written] = '\0';
183 return written;
184}
185
186Error Name::encode(uint8_t* buf, size_t bufSize, size_t& encodedLen) const {
187 // Internal buffer stores only component TLVs
188 // Build the entire Name TLV
189
190 const size_t nameValueLen = length_; // Total length of component TLVs
191 const size_t headerSize = varNumberSize(tlv::Name) + varNumberSize(nameValueLen);
192 const size_t totalSize = headerSize + nameValueLen;
193
194 if (bufSize < totalSize) {
195 return Error::BufferTooSmall;
196 }
197
198 TlvEncoder encoder(buf, bufSize);
199
200 Error err = encoder.writeType(tlv::Name);
201 if (err != Error::Success) {
202 return err;
203 }
204
205 err = encoder.writeLength(nameValueLen);
206 if (err != Error::Success) {
207 return err;
208 }
209
210 err = encoder.writeBytes(buffer_.data(), length_);
211 if (err != Error::Success) {
212 return err;
213 }
214
215 encodedLen = encoder.size();
216 return Error::Success;
217}
218
219NameComponent Name::component(size_t index) const {
220 if (index >= numComponents_) {
221 return {.value = nullptr, .size = 0};
222 }
223
224 const auto& comp = components_[index];
225 return {.value = buffer_.data() + comp.offset, .size = comp.length};
226}
227
228Error Name::appendComponent(std::string_view comp) {
229 return appendComponentInternal(reinterpret_cast<const uint8_t*>(comp.data()), comp.size());
230}
231
232Error Name::appendComponent(const uint8_t* value, size_t len) {
233 return appendComponentInternal(value, len);
234}
235
236Error Name::appendComponentInternal(const uint8_t* value, size_t len) {
237 if (numComponents_ >= NAME_MAX_COMPONENTS) {
238 return Error::TooManyComponents;
239 }
240
241 // Calculate component TLV size
242 const size_t tlvSize = varNumberSize(tlv::GenericNameComponent) + varNumberSize(len) + len;
243
244 if (length_ + tlvSize > NAME_MAX_LENGTH) {
245 return Error::NameTooLong;
246 }
247
248 // Store as TLV in the buffer
249 TlvEncoder encoder(buffer_.data() + length_, buffer_.size() - length_);
250
251 Error err = encoder.writeType(tlv::GenericNameComponent);
252 if (err != Error::Success) {
253 return err;
254 }
255
256 err = encoder.writeLength(len);
257 if (err != Error::Success) {
258 return err;
259 }
260
261 // Record the offset of the component value
262 const size_t valueOffset = length_ + encoder.size();
263
264 err = encoder.writeBytes(value, len);
265 if (err != Error::Success) {
266 return err;
267 }
268
269 // Record component information
270 components_[numComponents_].offset = static_cast<uint16_t>(valueOffset);
271 components_[numComponents_].length = static_cast<uint16_t>(len);
272 numComponents_++;
273
274 length_ += encoder.size();
275
276 return Error::Success;
277}
278
279int Name::compare(const Name& other) const {
280 const size_t minComponents =
281 (numComponents_ < other.numComponents_) ? numComponents_ : other.numComponents_;
282
283 for (size_t i = 0; i < minComponents; ++i) {
284 const NameComponent a = component(i);
285 const NameComponent b = other.component(i);
286
287 // Compare by length
288 if (a.size != b.size) {
289 return (a.size < b.size) ? -1 : 1;
290 }
291
292 // Compare by byte sequence
293 const int cmp = std::memcmp(a.value, b.value, a.size);
294 if (cmp != 0) {
295 return cmp;
296 }
297 }
298
299 // Compare by number of components
300 if (numComponents_ < other.numComponents_) {
301 return -1;
302 }
303 if (numComponents_ > other.numComponents_) {
304 return 1;
305 }
306 return 0;
307}
308
309bool Name::equals(const Name& other) const {
310 return compare(other) == 0;
311}
312
313bool Name::isPrefixOf(const Name& other) const {
314 if (numComponents_ > other.numComponents_) {
315 return false;
316 }
317
318 for (size_t i = 0; i < numComponents_; ++i) {
319 const NameComponent a = component(i);
320 const NameComponent b = other.component(i);
321
322 if (a.size != b.size) {
323 return false;
324 }
325
326 if (std::memcmp(a.value, b.value, a.size) != 0) {
327 return false;
328 }
329 }
330
331 return true;
332}
333
334uint32_t Name::hash() const {
335 // Simple DJB2 hash
336 uint32_t h = 5381;
337 for (size_t i = 0; i < length_; ++i) {
338 h = ((h << 5) + h) + buffer_[i];
339 }
340 return h;
341}
342
343} // namespace ndn
NDN Name class.
Definition name.hpp:64
Error encode(uint8_t *buf, size_t bufSize, size_t &encodedLen) const
Encode the Name to TLV wire format.
Definition name.cpp:186
static Result< Name > fromWire(const uint8_t *buf, size_t len, size_t *bytesRead=nullptr)
Decode a Name from TLV wire format.
Definition name.cpp:84
uint32_t hash() const
Compute hash value of the Name.
Definition name.cpp:334
Error appendComponent(std::string_view comp)
Append a string component.
Definition name.cpp:228
size_t toUri(char *buf, size_t bufSize) const
Convert the Name to a URI string.
Definition name.cpp:141
int compare(const Name &other) const
Compare with another Name.
Definition name.cpp:279
NameComponent component(size_t index) const
Get the component at a given index.
Definition name.cpp:219
bool equals(const Name &other) const
Check equality with another Name.
Definition name.cpp:309
bool isPrefixOf(const Name &other) const
Check if this Name is a prefix of another Name.
Definition name.cpp:313
static Result< Name > fromUri(std::string_view uri)
Create a Name from a URI string.
Definition name.cpp:25
TLV decoder.
Definition tlv.hpp:235
size_t position() const
Get current position.
Definition tlv.hpp:320
const uint8_t * current() const
Pointer to current position.
Definition tlv.hpp:308
Result< TlvHeader > readTlvHeader()
Read a TLV header (Type and Length) at once.
Definition tlv.cpp:224
Error skip(size_t len)
Skip a specified number of bytes.
Definition tlv.cpp:248
size_t remaining() const
Remaining readable bytes.
Definition tlv.hpp:302
TLV encoder.
Definition tlv.hpp:116
Error writeLength(size_t length)
Write a TLV Length.
Definition tlv.cpp:91
Error writeBytes(const uint8_t *data, size_t len)
Write a byte sequence.
Definition tlv.cpp:95
size_t size() const
Current write position (= number of bytes written)
Definition tlv.hpp:189
Error writeType(uint32_t type)
Write a TLV Type.
Definition tlv.cpp:87
constexpr size_t NAME_MAX_LENGTH
Maximum Name length (bytes)
Definition common.hpp:110
Error
Error codes.
Definition common.hpp:24
NDN Name class.
constexpr uint32_t Name
Name.
Definition tlv.hpp:34
constexpr uint32_t GenericNameComponent
Generic Name component.
Definition tlv.hpp:40
Name component.
Definition name.hpp:26
const uint8_t * value
Pointer to the component value.
Definition name.hpp:27
size_t size
Size of the component in bytes.
Definition name.hpp:28
Result type template.
Definition common.hpp:147
NDN TLV (Type-Length-Value) encoding.
constexpr size_t varNumberSize(uint64_t value)
Calculate the encoded size of a VAR-NUMBER.
Definition tlv.hpp:339