@mikrojs/native 0.12.0 → 0.14.0-pr-229.g0d8db1b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,706 @@
1
+ /*
2
+ * SPDX-License-Identifier: CC0-1.0
3
+ */
4
+
5
+ /**
6
+ * @ingroup nanocbor
7
+ * @{
8
+ * @file
9
+ * @brief Minimalistic CBOR decoder implementation
10
+ *
11
+ * @author Koen Zandberg <koen@bergzand.net>
12
+ * @}
13
+ */
14
+
15
+ #include <stddef.h>
16
+ #include <stdint.h>
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+
20
+ #include "nanocbor/config.h"
21
+ #include "nanocbor/nanocbor.h"
22
+
23
+ #include NANOCBOR_BYTEORDER_HEADER
24
+
25
+ void nanocbor_decoder_init(nanocbor_value_t *value, const uint8_t *buf,
26
+ size_t len)
27
+ {
28
+ value->cur = buf;
29
+ value->end = buf + len;
30
+ value->flags = 0;
31
+ }
32
+
33
+ static void _advance(nanocbor_value_t *cvalue, unsigned int res)
34
+ {
35
+ cvalue->cur += res;
36
+ cvalue->remaining--;
37
+ }
38
+
39
+ static int _advance_if(nanocbor_value_t *cvalue, int res)
40
+ {
41
+ if (res > 0) {
42
+ _advance(cvalue, (unsigned int)res);
43
+ }
44
+ return res;
45
+ }
46
+
47
+ static inline bool _over_end(const nanocbor_value_t *it)
48
+ {
49
+ return it->cur >= it->end;
50
+ }
51
+
52
+ static inline uint8_t _get_type(const nanocbor_value_t *value)
53
+ {
54
+ return (*value->cur & NANOCBOR_TYPE_MASK);
55
+ }
56
+
57
+ static int _value_match_exact(nanocbor_value_t *cvalue, uint8_t val)
58
+ {
59
+ int res = NANOCBOR_ERR_INVALID_TYPE;
60
+
61
+ if (_over_end(cvalue)) {
62
+ res = NANOCBOR_ERR_END;
63
+ }
64
+ else if (*cvalue->cur == val) {
65
+ _advance(cvalue, 1U);
66
+ res = NANOCBOR_OK;
67
+ }
68
+ return res;
69
+ }
70
+
71
+ bool nanocbor_at_end(const nanocbor_value_t *it)
72
+ {
73
+ bool end = false;
74
+ /* The container is at the end when */
75
+ if (_over_end(it) || /* Number of items exhausted */
76
+ /* Indefinite container and the current item is the end marker */
77
+ ((nanocbor_container_indefinite(it)
78
+ && *it->cur
79
+ == (NANOCBOR_TYPE_FLOAT << NANOCBOR_TYPE_OFFSET
80
+ | NANOCBOR_VALUE_MASK)))
81
+ ||
82
+ /* Or the remaining number of items is zero */
83
+ (!nanocbor_container_indefinite(it) && nanocbor_in_container(it)
84
+ && it->remaining == 0)) {
85
+ end = true;
86
+ }
87
+ return end;
88
+ }
89
+
90
+ int nanocbor_get_type(const nanocbor_value_t *value)
91
+ {
92
+ if (nanocbor_at_end(value)) {
93
+ return NANOCBOR_ERR_END;
94
+ }
95
+ return (_get_type(value) >> NANOCBOR_TYPE_OFFSET);
96
+ }
97
+
98
+ static int _get_uint64(const nanocbor_value_t *cvalue, uint64_t *value,
99
+ uint8_t max, int type)
100
+ {
101
+ int ctype = nanocbor_get_type(cvalue);
102
+
103
+ if (ctype < 0) {
104
+ return ctype;
105
+ }
106
+
107
+ if (type != ctype) {
108
+ return NANOCBOR_ERR_INVALID_TYPE;
109
+ }
110
+ unsigned bytelen = *cvalue->cur & NANOCBOR_VALUE_MASK;
111
+
112
+ if (bytelen < NANOCBOR_SIZE_BYTE) {
113
+ *value = bytelen;
114
+ /* Ptr should advance 1 pos */
115
+ return 1;
116
+ }
117
+ if (bytelen > max) {
118
+ return NANOCBOR_ERR_OVERFLOW;
119
+ }
120
+
121
+ unsigned bytes = 1U << (bytelen - NANOCBOR_SIZE_BYTE);
122
+
123
+ if ((cvalue->cur + bytes) >= cvalue->end) {
124
+ return NANOCBOR_ERR_END;
125
+ }
126
+ uint64_t tmp = 0;
127
+ /* Copy the value from cbor to the least significant bytes */
128
+ memcpy(((uint8_t *)&tmp) + sizeof(uint64_t) - bytes, cvalue->cur + 1U,
129
+ bytes);
130
+ /* NOLINTNEXTLINE: user supplied function */
131
+ tmp = NANOCBOR_BE64TOH_FUNC(tmp);
132
+ *value = 0;
133
+ memcpy(value, &tmp, bytes);
134
+
135
+ return (int)(1 + bytes);
136
+ }
137
+
138
+ static int _get_and_advance_uint8(nanocbor_value_t *cvalue, uint8_t *value,
139
+ int type)
140
+ {
141
+ uint64_t tmp = 0;
142
+ int res = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_BYTE, type);
143
+ *value = (uint8_t)tmp;
144
+
145
+ return _advance_if(cvalue, res);
146
+ }
147
+
148
+ static int _get_and_advance_uint16(nanocbor_value_t *cvalue, uint16_t *value,
149
+ int type)
150
+ {
151
+ uint64_t tmp = 0;
152
+ int res = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_SHORT, type);
153
+ *value = (uint16_t)tmp;
154
+
155
+ return _advance_if(cvalue, res);
156
+ }
157
+
158
+ static int _get_and_advance_uint32(nanocbor_value_t *cvalue, uint32_t *value,
159
+ int type)
160
+ {
161
+ uint64_t tmp = 0;
162
+ int res = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_WORD, type);
163
+ *value = tmp;
164
+
165
+ return _advance_if(cvalue, res);
166
+ }
167
+
168
+ static int _get_and_advance_uint64(nanocbor_value_t *cvalue, uint64_t *value,
169
+ int type)
170
+ {
171
+ uint64_t tmp = 0;
172
+ int res = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_LONG, type);
173
+ *value = tmp;
174
+
175
+ return _advance_if(cvalue, res);
176
+ }
177
+
178
+ int nanocbor_get_uint8(nanocbor_value_t *cvalue, uint8_t *value)
179
+ {
180
+ return _get_and_advance_uint8(cvalue, value, NANOCBOR_TYPE_UINT);
181
+ }
182
+
183
+ int nanocbor_get_uint16(nanocbor_value_t *cvalue, uint16_t *value)
184
+ {
185
+ return _get_and_advance_uint16(cvalue, value, NANOCBOR_TYPE_UINT);
186
+ }
187
+
188
+ int nanocbor_get_uint32(nanocbor_value_t *cvalue, uint32_t *value)
189
+ {
190
+ return _get_and_advance_uint32(cvalue, value, NANOCBOR_TYPE_UINT);
191
+ }
192
+
193
+ int nanocbor_get_uint64(nanocbor_value_t *cvalue, uint64_t *value)
194
+ {
195
+ return _get_and_advance_uint64(cvalue, value, NANOCBOR_TYPE_UINT);
196
+ }
197
+
198
+ static int _get_and_advance_int64(nanocbor_value_t *cvalue, int64_t *value,
199
+ uint8_t max, uint64_t bound)
200
+ {
201
+ int type = nanocbor_get_type(cvalue);
202
+ if (type < 0) {
203
+ return type;
204
+ }
205
+ int res = NANOCBOR_ERR_INVALID_TYPE;
206
+ if (type == NANOCBOR_TYPE_NINT || type == NANOCBOR_TYPE_UINT) {
207
+ uint64_t intermediate = 0;
208
+ res = _get_uint64(cvalue, &intermediate, max, type);
209
+ if (intermediate > bound) {
210
+ res = NANOCBOR_ERR_OVERFLOW;
211
+ }
212
+ if (type == NANOCBOR_TYPE_NINT) {
213
+ *value = (-(int64_t)intermediate) - 1;
214
+ }
215
+ else {
216
+ *value = (int64_t)intermediate;
217
+ }
218
+ }
219
+ return _advance_if(cvalue, res);
220
+ }
221
+
222
+ int nanocbor_get_int8(nanocbor_value_t *cvalue, int8_t *value)
223
+ {
224
+ int64_t tmp = 0;
225
+ int res
226
+ = _get_and_advance_int64(cvalue, &tmp, NANOCBOR_SIZE_BYTE, INT8_MAX);
227
+
228
+ *value = (int8_t)tmp;
229
+
230
+ return res;
231
+ }
232
+
233
+ int nanocbor_get_int16(nanocbor_value_t *cvalue, int16_t *value)
234
+ {
235
+ int64_t tmp = 0;
236
+ int res
237
+ = _get_and_advance_int64(cvalue, &tmp, NANOCBOR_SIZE_SHORT, INT16_MAX);
238
+
239
+ *value = (int16_t)tmp;
240
+
241
+ return res;
242
+ }
243
+
244
+ int nanocbor_get_int32(nanocbor_value_t *cvalue, int32_t *value)
245
+ {
246
+ int64_t tmp = 0;
247
+ int res
248
+ = _get_and_advance_int64(cvalue, &tmp, NANOCBOR_SIZE_WORD, INT32_MAX);
249
+
250
+ *value = (int32_t)tmp;
251
+
252
+ return res;
253
+ }
254
+
255
+ int nanocbor_get_int64(nanocbor_value_t *cvalue, int64_t *value)
256
+ {
257
+ return _get_and_advance_int64(cvalue, value, NANOCBOR_SIZE_LONG, INT64_MAX);
258
+ }
259
+
260
+ int nanocbor_get_tag(nanocbor_value_t *cvalue, uint32_t *tag)
261
+ {
262
+ uint64_t tmp = 0;
263
+ int res = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_WORD, NANOCBOR_TYPE_TAG);
264
+
265
+ if (res >= 0) {
266
+ cvalue->cur += res;
267
+ res = NANOCBOR_OK;
268
+ }
269
+ *tag = (uint32_t)tmp;
270
+
271
+ return res;
272
+ }
273
+
274
+ int nanocbor_get_tag64(nanocbor_value_t *cvalue, uint64_t *tag)
275
+ {
276
+ return _get_and_advance_uint64(cvalue, tag, NANOCBOR_TYPE_TAG);
277
+ }
278
+
279
+ int nanocbor_get_decimal_frac(nanocbor_value_t *cvalue, int32_t *e, int32_t *m)
280
+ {
281
+ int res = NANOCBOR_NOT_FOUND;
282
+ uint32_t tag = UINT32_MAX;
283
+ if (nanocbor_get_tag(cvalue, &tag) == NANOCBOR_OK) {
284
+ if (tag == NANOCBOR_TAG_DEC_FRAC) {
285
+ nanocbor_value_t arr;
286
+ if (nanocbor_enter_array(cvalue, &arr) == NANOCBOR_OK) {
287
+ res = nanocbor_get_int32(&arr, e);
288
+ if (res >= 0) {
289
+ res = nanocbor_get_int32(&arr, m);
290
+ if (res >= 0) {
291
+ res = NANOCBOR_OK;
292
+ }
293
+ }
294
+ nanocbor_leave_container(cvalue, &arr);
295
+ }
296
+ }
297
+ }
298
+
299
+ return res;
300
+ }
301
+
302
+ static int _get_str(nanocbor_value_t *cvalue, const uint8_t **buf, size_t *len,
303
+ uint8_t type)
304
+ {
305
+ uint64_t tmp = 0;
306
+ int res = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_SIZET, type);
307
+ *len = tmp;
308
+
309
+ if (cvalue->end - cvalue->cur < 0
310
+ || (size_t)(cvalue->end - cvalue->cur) < *len) {
311
+ return NANOCBOR_ERR_END;
312
+ }
313
+ if (res >= 0) {
314
+ *buf = (cvalue->cur) + res;
315
+ _advance(cvalue, (unsigned int)((size_t)res + *len));
316
+ res = NANOCBOR_OK;
317
+ }
318
+ return res;
319
+ }
320
+
321
+ int nanocbor_get_bstr(nanocbor_value_t *cvalue, const uint8_t **buf,
322
+ size_t *len)
323
+ {
324
+ return _get_str(cvalue, buf, len, NANOCBOR_TYPE_BSTR);
325
+ }
326
+
327
+ int nanocbor_get_tstr(nanocbor_value_t *cvalue, const uint8_t **buf,
328
+ size_t *len)
329
+ {
330
+ return _get_str(cvalue, buf, len, NANOCBOR_TYPE_TSTR);
331
+ }
332
+
333
+ int nanocbor_get_null(nanocbor_value_t *cvalue)
334
+ {
335
+ return _value_match_exact(cvalue,
336
+ NANOCBOR_MASK_FLOAT | NANOCBOR_SIMPLE_NULL);
337
+ }
338
+
339
+ int nanocbor_get_bool(nanocbor_value_t *cvalue, bool *value)
340
+ {
341
+ int res = _value_match_exact(cvalue,
342
+ NANOCBOR_MASK_FLOAT | NANOCBOR_SIMPLE_FALSE);
343
+ if (res >= NANOCBOR_OK) {
344
+ *value = false;
345
+ } else {
346
+ res = _value_match_exact(cvalue,
347
+ NANOCBOR_MASK_FLOAT | NANOCBOR_SIMPLE_TRUE);
348
+ if (res >= NANOCBOR_OK) {
349
+ *value = true;
350
+ }
351
+ }
352
+
353
+ return res;
354
+ }
355
+
356
+ int nanocbor_get_undefined(nanocbor_value_t *cvalue)
357
+ {
358
+ return _value_match_exact(cvalue,
359
+ NANOCBOR_MASK_FLOAT | NANOCBOR_SIMPLE_UNDEF);
360
+ }
361
+
362
+ int nanocbor_get_simple(nanocbor_value_t *cvalue, uint8_t *value)
363
+ {
364
+ int res = _get_and_advance_uint8(cvalue, value, NANOCBOR_TYPE_FLOAT);
365
+ if (res == NANOCBOR_ERR_OVERFLOW) {
366
+ res = NANOCBOR_ERR_INVALID_TYPE;
367
+ }
368
+ return res > 0 ? NANOCBOR_OK : res;
369
+ }
370
+
371
+ /* float bit mask related defines */
372
+ #define FLOAT_EXP_OFFSET (127U)
373
+ #define FLOAT_SIZE (32U)
374
+ #define FLOAT_EXP_POS (23U)
375
+ #define FLOAT_EXP_MASK ((uint32_t)0xFFU)
376
+ #define FLOAT_SIGN_POS (31U)
377
+ #define FLOAT_FRAC_MASK (0x7FFFFFU)
378
+ #define FLOAT_SIGN_MASK ((uint32_t)1U << FLOAT_SIGN_POS)
379
+ #define FLOAT_EXP_IS_NAN (0xFFU)
380
+ #define FLOAT_IS_ZERO (~(FLOAT_SIGN_MASK))
381
+ /* Part where a float to halffloat leads to precision loss */
382
+ #define FLOAT_HALF_LOSS (0x1FFFU)
383
+
384
+ /* halffloat bit mask related defines */
385
+ #define HALF_EXP_OFFSET (15U)
386
+ #define HALF_SIZE (16U)
387
+ #define HALF_EXP_POS (10U)
388
+ #define HALF_EXP_MASK (0x1FU)
389
+ #define HALF_SIGN_POS (15U)
390
+ #define HALF_FRAC_MASK (0x3FFU)
391
+ #define HALF_SIGN_MASK ((uint16_t)(1U << HALF_SIGN_POS))
392
+ #define HALF_MASK_HALF (0xFFU)
393
+
394
+ #define HALF_FLOAT_EXP_DIFF ((uint16_t)(FLOAT_EXP_OFFSET - HALF_EXP_OFFSET))
395
+ #define HALF_FLOAT_EXP_POS_DIFF ((uint16_t)(FLOAT_EXP_POS - HALF_EXP_POS))
396
+ #define HALF_EXP_TO_FLOAT (HALF_FLOAT_EXP_DIFF << HALF_EXP_POS)
397
+
398
+ static int _decode_half_float(nanocbor_value_t *cvalue, float *value)
399
+ {
400
+ uint64_t tmp = 0;
401
+ int res
402
+ = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_SHORT, NANOCBOR_TYPE_FLOAT);
403
+ if (res == 1 + sizeof(uint16_t)) {
404
+ uint32_t *ifloat = (uint32_t *)value;
405
+ *ifloat = (tmp & HALF_SIGN_MASK) << (FLOAT_SIGN_POS - HALF_SIGN_POS);
406
+
407
+ uint32_t significant = tmp & HALF_FRAC_MASK;
408
+ uint32_t exponent = tmp & (HALF_EXP_MASK << HALF_EXP_POS);
409
+
410
+ static const uint32_t magic = ((uint32_t)FLOAT_EXP_OFFSET - 1)
411
+ << FLOAT_EXP_POS;
412
+ static const float *fmagic = (float *)&magic;
413
+
414
+ if (exponent == 0) {
415
+ *ifloat = magic + significant;
416
+ *value -= *fmagic;
417
+ }
418
+ else {
419
+ if (exponent == (HALF_EXP_MASK << HALF_EXP_POS)) {
420
+ /* Set exponent to max value */
421
+ exponent
422
+ = ((FLOAT_EXP_MASK - HALF_FLOAT_EXP_DIFF) << HALF_EXP_POS);
423
+ }
424
+ *ifloat
425
+ |= ((exponent + HALF_EXP_TO_FLOAT) << HALF_FLOAT_EXP_POS_DIFF)
426
+ | (significant << HALF_FLOAT_EXP_POS_DIFF);
427
+ }
428
+ return _advance_if(cvalue, res);
429
+ }
430
+ return res > 0 ? NANOCBOR_ERR_INVALID_TYPE : res;
431
+ }
432
+
433
+ static int _decode_float(nanocbor_value_t *cvalue, float *value)
434
+ {
435
+ uint64_t tmp = 0;
436
+ int res
437
+ = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_WORD, NANOCBOR_TYPE_FLOAT);
438
+ if (res == 1 + sizeof(uint32_t)) {
439
+ uint32_t ifloat = tmp;
440
+ memcpy(value, &ifloat, sizeof(uint32_t));
441
+ return _advance_if(cvalue, res);
442
+ }
443
+ return res > 0 ? NANOCBOR_ERR_INVALID_TYPE : res;
444
+ }
445
+
446
+ static int _decode_double(nanocbor_value_t *cvalue, double *value)
447
+ {
448
+ uint64_t tmp = 0;
449
+ int res
450
+ = _get_uint64(cvalue, &tmp, NANOCBOR_SIZE_LONG, NANOCBOR_TYPE_FLOAT);
451
+ if (res == 1 + sizeof(uint64_t)) {
452
+ uint64_t ifloat = tmp;
453
+ memcpy(value, &ifloat, sizeof(uint64_t));
454
+ return _advance_if(cvalue, res);
455
+ }
456
+ return res > 0 ? NANOCBOR_ERR_INVALID_TYPE : res;
457
+ }
458
+
459
+ int nanocbor_get_float(nanocbor_value_t *cvalue, float *value)
460
+ {
461
+ int res = _decode_half_float(cvalue, value);
462
+ if (res < 0) {
463
+ res = _decode_float(cvalue, value);
464
+ }
465
+ return res;
466
+ }
467
+
468
+ int nanocbor_get_double(nanocbor_value_t *cvalue, double *value)
469
+ {
470
+ float tmp = 0;
471
+ int res = nanocbor_get_float(cvalue, &tmp);
472
+ if (res >= NANOCBOR_OK) {
473
+ *value = tmp;
474
+ return res;
475
+ }
476
+ return _decode_double(cvalue, value);
477
+ }
478
+
479
+ /**
480
+ * @brief Used internally to signal indefinite container length.
481
+ *
482
+ * Should not be passed out of user-facing API.
483
+ */
484
+ #define NANOCBOR_ERR_INDEFINITE -42
485
+
486
+ /**
487
+ * @brief Check the upcoming CBOR item to be a container and return its raw length.
488
+ *
489
+ * @param[in] it CBOR value to decode from
490
+ * @param[out] len raw length of container (aka number of array elements or map entries)
491
+ *
492
+ * @return NANOCBOR_OK on success
493
+ * @return NANOCBOR_ERR_INDEFINITE if the upcoming CBOR item is an indefinite container
494
+ * @return other negative on error
495
+ */
496
+ static int _check_upcoming_container_length(const nanocbor_value_t *it,
497
+ uint64_t *len, uint8_t type)
498
+ {
499
+ uint8_t value_match = (uint8_t)(((unsigned)type << NANOCBOR_TYPE_OFFSET)
500
+ | NANOCBOR_SIZE_INDEFINITE);
501
+
502
+ /* Not using _value_match_exact here to keep *it const */
503
+ if (!_over_end(it) && *it->cur == value_match) {
504
+ return NANOCBOR_ERR_INDEFINITE;
505
+ }
506
+
507
+ return _get_uint64(it, len, NANOCBOR_SIZE_LONG, type);
508
+ }
509
+
510
+ static int _enter_container(const nanocbor_value_t *it,
511
+ nanocbor_value_t *container, uint8_t type)
512
+ {
513
+ container->end = it->end;
514
+ container->remaining = 0;
515
+
516
+ int res = _check_upcoming_container_length(it, &container->remaining, type);
517
+ if (res == NANOCBOR_ERR_INDEFINITE) {
518
+ container->flags = NANOCBOR_DECODER_FLAG_INDEFINITE
519
+ | NANOCBOR_DECODER_FLAG_CONTAINER;
520
+ container->cur = it->cur + 1;
521
+ return NANOCBOR_OK;
522
+ }
523
+ if (res < 0) {
524
+ return res;
525
+ }
526
+ container->flags = NANOCBOR_DECODER_FLAG_CONTAINER;
527
+ container->cur = it->cur + res;
528
+ return NANOCBOR_OK;
529
+ }
530
+
531
+ int nanocbor_enter_array(const nanocbor_value_t *it, nanocbor_value_t *array)
532
+ {
533
+ return _enter_container(it, array, NANOCBOR_TYPE_ARR);
534
+ }
535
+
536
+ int nanocbor_enter_map(const nanocbor_value_t *it, nanocbor_value_t *map)
537
+ {
538
+ int res = _enter_container(it, map, NANOCBOR_TYPE_MAP);
539
+
540
+ if (map->remaining > UINT64_MAX / 2) {
541
+ return NANOCBOR_ERR_OVERFLOW;
542
+ }
543
+ map->remaining = map->remaining * 2;
544
+ return res;
545
+ }
546
+
547
+ int nanocbor_leave_container(nanocbor_value_t *it, nanocbor_value_t *container)
548
+ {
549
+ /* check `container` to be a valid, fully consumed container that is plausible to have been entered from `it` */
550
+ if (!nanocbor_in_container(container) ||
551
+ !nanocbor_at_end(container) ||
552
+ container->cur <= it->cur ||
553
+ container->cur > it->end) {
554
+ return NANOCOBR_PANIC_INVALID_OPERATION;
555
+ }
556
+ if (it->remaining) {
557
+ it->remaining--;
558
+ }
559
+ if (nanocbor_container_indefinite(container)) {
560
+ it->cur = container->cur + 1;
561
+ }
562
+ else {
563
+ it->cur = container->cur;
564
+ }
565
+ return NANOCBOR_OK;
566
+ }
567
+
568
+ static int _skip_simple(nanocbor_value_t *it)
569
+ {
570
+ int type = nanocbor_get_type(it);
571
+ uint64_t tmp = 0;
572
+ if (type == NANOCBOR_TYPE_BSTR || type == NANOCBOR_TYPE_TSTR) {
573
+ const uint8_t *tmp = NULL;
574
+ size_t len = 0;
575
+ return _get_str(it, &tmp, &len, (uint8_t)type);
576
+ }
577
+ int res = _get_uint64(it, &tmp, NANOCBOR_SIZE_LONG, type);
578
+ res = _advance_if(it, res);
579
+ return res > 0 ? NANOCBOR_OK : res;
580
+ }
581
+
582
+ int nanocbor_get_subcbor(nanocbor_value_t *it, const uint8_t **start,
583
+ size_t *len)
584
+ {
585
+ *start = it->cur;
586
+ int res = nanocbor_skip(it);
587
+ *len = (size_t)(it->cur - *start);
588
+ return res;
589
+ }
590
+
591
+ int nanocbor_skip_simple(nanocbor_value_t *it)
592
+ {
593
+ return _skip_simple(it);
594
+ }
595
+
596
+ /* NOLINTNEXTLINE(misc-no-recursion): Recursion is limited by design */
597
+ static int _skip_limited(nanocbor_value_t *it, uint8_t limit)
598
+ {
599
+ if (limit == 0) {
600
+ return NANOCBOR_ERR_RECURSION;
601
+ }
602
+
603
+ int res = NANOCBOR_OK;
604
+ uint64_t skip = 1;
605
+
606
+ while (skip > 0) {
607
+ int type = nanocbor_get_type(it);
608
+ if (type < 0) {
609
+ return type;
610
+ }
611
+
612
+ /* map or array */
613
+ if (type == NANOCBOR_TYPE_ARR || type == NANOCBOR_TYPE_MAP) {
614
+ uint64_t len = 0;
615
+ res = _check_upcoming_container_length(it, &len, type);
616
+ if (res == NANOCBOR_ERR_INDEFINITE) {
617
+ /* cannot handle indefinite-length containers linearily,
618
+ * use stack (recursion) instead */
619
+ nanocbor_value_t recurse;
620
+ res = _enter_container(it, &recurse, type);
621
+ if (res < 0) {
622
+ return res;
623
+ }
624
+ while (!nanocbor_at_end(&recurse)) {
625
+ res = _skip_limited(&recurse, limit - 1);
626
+ if (res < 0) {
627
+ return res;
628
+ }
629
+ }
630
+ nanocbor_leave_container(it, &recurse);
631
+ skip--;
632
+ continue;
633
+ }
634
+ if (res < 0) {
635
+ /* propagate (other) errors up */
636
+ return res;
637
+ }
638
+ _advance(it, res);
639
+
640
+ if (type == NANOCBOR_TYPE_MAP) {
641
+ if (len > UINT64_MAX / 2) {
642
+ return NANOCBOR_ERR_OVERFLOW;
643
+ }
644
+ len *= 2;
645
+ }
646
+ if (len > UINT64_MAX - skip) {
647
+ return NANOCBOR_ERR_OVERFLOW;
648
+ }
649
+ skip += len - 1;
650
+ continue;
651
+ }
652
+ else if (type == NANOCBOR_TYPE_TAG) {
653
+ uint64_t tmp = 0;
654
+ int res = _get_uint64(it, &tmp, NANOCBOR_SIZE_WORD, type);
655
+ if (res < 0) {
656
+ return res;
657
+ }
658
+ _advance(it, res);
659
+ /* do not decrement skip as tag content still needs to be skipped, too */
660
+ continue;
661
+ }
662
+
663
+ res = _skip_simple(it);
664
+ if (res < 0) {
665
+ return res;
666
+ }
667
+ skip--;
668
+ }
669
+
670
+ return NANOCBOR_OK;
671
+ }
672
+
673
+ int nanocbor_skip(nanocbor_value_t *it)
674
+ {
675
+ return _skip_limited(it, NANOCBOR_RECURSION_MAX);
676
+ }
677
+
678
+ int nanocbor_get_key_tstr(nanocbor_value_t *start, const char *key,
679
+ nanocbor_value_t *value)
680
+ {
681
+ int res = NANOCBOR_NOT_FOUND;
682
+ size_t len = strlen(key);
683
+ *value = *start;
684
+
685
+ while (!nanocbor_at_end(value)) {
686
+ const uint8_t *s = NULL;
687
+ size_t s_len = 0;
688
+
689
+ res = nanocbor_get_tstr(value, &s, &s_len);
690
+ if (res < 0) {
691
+ break;
692
+ }
693
+
694
+ if (s_len == len && !strncmp(key, (const char *)s, len)) {
695
+ res = NANOCBOR_OK;
696
+ break;
697
+ }
698
+
699
+ res = nanocbor_skip(value);
700
+ if (res < 0) {
701
+ break;
702
+ }
703
+ }
704
+
705
+ return res;
706
+ }