Coverage Report

Created: 2026-02-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcbor/src/cbor.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3
 *
4
 * libcbor is free software; you can redistribute it and/or modify
5
 * it under the terms of the MIT license. See LICENSE for details.
6
 */
7
8
#include <stdbool.h>
9
#include <string.h>
10
11
#include "cbor.h"
12
#include "cbor/internal/builder_callbacks.h"
13
#include "cbor/internal/loaders.h"
14
#include "cbor/internal/memory_utils.h"
15
16
cbor_item_t* cbor_load(cbor_data source, size_t source_size,
17
3.64k
                       struct cbor_load_result* result) {
18
  /* Context stack */
19
3.64k
  static struct cbor_callbacks callbacks = {
20
3.64k
      .uint8 = &cbor_builder_uint8_callback,
21
3.64k
      .uint16 = &cbor_builder_uint16_callback,
22
3.64k
      .uint32 = &cbor_builder_uint32_callback,
23
3.64k
      .uint64 = &cbor_builder_uint64_callback,
24
25
3.64k
      .negint8 = &cbor_builder_negint8_callback,
26
3.64k
      .negint16 = &cbor_builder_negint16_callback,
27
3.64k
      .negint32 = &cbor_builder_negint32_callback,
28
3.64k
      .negint64 = &cbor_builder_negint64_callback,
29
30
3.64k
      .byte_string = &cbor_builder_byte_string_callback,
31
3.64k
      .byte_string_start = &cbor_builder_byte_string_start_callback,
32
33
3.64k
      .string = &cbor_builder_string_callback,
34
3.64k
      .string_start = &cbor_builder_string_start_callback,
35
36
3.64k
      .array_start = &cbor_builder_array_start_callback,
37
3.64k
      .indef_array_start = &cbor_builder_indef_array_start_callback,
38
39
3.64k
      .map_start = &cbor_builder_map_start_callback,
40
3.64k
      .indef_map_start = &cbor_builder_indef_map_start_callback,
41
42
3.64k
      .tag = &cbor_builder_tag_callback,
43
44
3.64k
      .null = &cbor_builder_null_callback,
45
3.64k
      .undefined = &cbor_builder_undefined_callback,
46
3.64k
      .boolean = &cbor_builder_boolean_callback,
47
3.64k
      .float2 = &cbor_builder_float2_callback,
48
3.64k
      .float4 = &cbor_builder_float4_callback,
49
3.64k
      .float8 = &cbor_builder_float8_callback,
50
3.64k
      .indef_break = &cbor_builder_indef_break_callback};
51
52
3.64k
  if (source_size == 0) {
53
0
    result->error.code = CBOR_ERR_NODATA;
54
0
    return NULL;
55
0
  }
56
3.64k
  struct _cbor_stack stack = _cbor_stack_init();
57
58
  /* Target for callbacks */
59
3.64k
  struct _cbor_decoder_context context = (struct _cbor_decoder_context){
60
3.64k
      .stack = &stack, .creation_failed = false, .syntax_error = false};
61
3.64k
  struct cbor_decoder_result decode_result;
62
3.64k
  *result =
63
3.64k
      (struct cbor_load_result){.read = 0, .error = {.code = CBOR_ERR_NONE}};
64
65
43.4M
  do {
66
43.4M
    if (source_size > result->read) { /* Check for overflows */
67
43.4M
      decode_result =
68
43.4M
          cbor_stream_decode(source + result->read, source_size - result->read,
69
43.4M
                             &callbacks, &context);
70
43.4M
    } else {
71
1.37k
      result->error = (struct cbor_error){.code = CBOR_ERR_NOTENOUGHDATA,
72
1.37k
                                          .position = result->read};
73
1.37k
      goto error;
74
1.37k
    }
75
76
43.4M
    switch (decode_result.status) {
77
43.4M
      case CBOR_DECODER_FINISHED:
78
        /* Everything OK */
79
43.4M
        {
80
43.4M
          result->read += decode_result.read;
81
43.4M
          break;
82
0
        }
83
551
      case CBOR_DECODER_NEDATA:
84
        /* Data length doesn't match MTB expectation */
85
551
        {
86
551
          result->error.code = CBOR_ERR_NOTENOUGHDATA;
87
551
          goto error;
88
0
        }
89
74
      case CBOR_DECODER_ERROR:
90
        /* Reserved/malformed item */
91
74
        {
92
74
          result->error.code = CBOR_ERR_MALFORMATED;
93
74
          goto error;
94
0
        }
95
43.4M
    }
96
97
43.4M
    if (context.creation_failed) {
98
      /* Most likely unsuccessful allocation - our callback has failed */
99
306
      result->error.code = CBOR_ERR_MEMERROR;
100
306
      goto error;
101
43.4M
    } else if (context.syntax_error) {
102
108
      result->error.code = CBOR_ERR_SYNTAXERROR;
103
108
      goto error;
104
108
    }
105
43.4M
  } while (stack.size > 0);
106
107
1.22k
  return context.root;
108
109
2.41k
error:
110
2.41k
  result->error.position = result->read;
111
  // debug_print("Failed with decoder error %d at %d\n", result->error.code,
112
  // result->error.position); cbor_describe(stack.top->item, stdout);
113
  /* Free the stack */
114
107k
  while (stack.size > 0) {
115
105k
    cbor_decref(&stack.top->item);
116
105k
    _cbor_stack_pop(&stack);
117
105k
  }
118
2.41k
  return NULL;
119
3.64k
}
120
121
14.2M
static cbor_item_t* _cbor_copy_int(cbor_item_t* item, bool negative) {
122
14.2M
  CBOR_ASSERT(cbor_isa_uint(item) || cbor_isa_negint(item));
123
14.2M
  CBOR_ASSERT(cbor_int_get_width(item) >= CBOR_INT_8 &&
124
14.2M
              cbor_int_get_width(item) <= CBOR_INT_64);
125
14.2M
  cbor_item_t* res = NULL;
126
14.2M
  switch (cbor_int_get_width(item)) {
127
13.7M
    case CBOR_INT_8:
128
13.7M
      res = cbor_build_uint8(cbor_get_uint8(item));
129
13.7M
      break;
130
31.8k
    case CBOR_INT_16:
131
31.8k
      res = cbor_build_uint16(cbor_get_uint16(item));
132
31.8k
      break;
133
489k
    case CBOR_INT_32:
134
489k
      res = cbor_build_uint32(cbor_get_uint32(item));
135
489k
      break;
136
7.70k
    case CBOR_INT_64:
137
7.70k
      res = cbor_build_uint64(cbor_get_uint64(item));
138
7.70k
      break;
139
14.2M
  }
140
141
14.2M
  if (negative) cbor_mark_negint(res);
142
143
14.2M
  return res;
144
14.2M
}
145
146
282k
static cbor_item_t* _cbor_copy_float_ctrl(cbor_item_t* item) {
147
282k
  CBOR_ASSERT(cbor_isa_float_ctrl(item));
148
282k
  CBOR_ASSERT(cbor_float_get_width(item) >= CBOR_FLOAT_0 &&
149
282k
              cbor_float_get_width(item) <= CBOR_FLOAT_64);
150
282k
  switch (cbor_float_get_width(item)) {
151
185k
    case CBOR_FLOAT_0:
152
185k
      return cbor_build_ctrl(cbor_ctrl_value(item));
153
76.8k
    case CBOR_FLOAT_16:
154
76.8k
      return cbor_build_float2(cbor_float_get_float2(item));
155
11.0k
    case CBOR_FLOAT_32:
156
11.0k
      return cbor_build_float4(cbor_float_get_float4(item));
157
8.81k
    case CBOR_FLOAT_64:
158
8.81k
      return cbor_build_float8(cbor_float_get_float8(item));
159
0
    default:  // LCOV_EXCL_START
160
0
      _CBOR_UNREACHABLE;
161
0
      return NULL;  // LCOV_EXCL_START
162
282k
  }
163
282k
}
164
165
24.7M
cbor_item_t* cbor_copy(cbor_item_t* item) {
166
24.7M
  CBOR_ASSERT_VALID_TYPE(cbor_typeof(item));
167
24.7M
  switch (cbor_typeof(item)) {
168
11.3M
    case CBOR_TYPE_UINT:
169
11.3M
      return _cbor_copy_int(item, false);
170
2.96M
    case CBOR_TYPE_NEGINT:
171
2.96M
      return _cbor_copy_int(item, true);
172
832k
    case CBOR_TYPE_BYTESTRING:
173
832k
      if (cbor_bytestring_is_definite(item)) {
174
831k
        return cbor_build_bytestring(cbor_bytestring_handle(item),
175
831k
                                     cbor_bytestring_length(item));
176
831k
      } else {
177
1.01k
        cbor_item_t* res = cbor_new_indefinite_bytestring();
178
1.01k
        if (res == NULL) {
179
0
          return NULL;
180
0
        }
181
182
746k
        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
183
745k
          cbor_item_t* chunk_copy =
184
745k
              cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
185
745k
          if (chunk_copy == NULL) {
186
0
            cbor_decref(&res);
187
0
            return NULL;
188
0
          }
189
745k
          if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
190
0
            cbor_decref(&chunk_copy);
191
0
            cbor_decref(&res);
192
0
            return NULL;
193
0
          }
194
745k
          cbor_decref(&chunk_copy);
195
745k
        }
196
1.01k
        return res;
197
1.01k
      }
198
450k
    case CBOR_TYPE_STRING:
199
450k
      if (cbor_string_is_definite(item)) {
200
447k
        return cbor_build_stringn((const char*)cbor_string_handle(item),
201
447k
                                  cbor_string_length(item));
202
447k
      } else {
203
2.83k
        cbor_item_t* res = cbor_new_indefinite_string();
204
2.83k
        if (res == NULL) {
205
0
          return NULL;
206
0
        }
207
208
262k
        for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
209
259k
          cbor_item_t* chunk_copy =
210
259k
              cbor_copy(cbor_string_chunks_handle(item)[i]);
211
259k
          if (chunk_copy == NULL) {
212
0
            cbor_decref(&res);
213
0
            return NULL;
214
0
          }
215
259k
          if (!cbor_string_add_chunk(res, chunk_copy)) {
216
0
            cbor_decref(&chunk_copy);
217
0
            cbor_decref(&res);
218
0
            return NULL;
219
0
          }
220
259k
          cbor_decref(&chunk_copy);
221
259k
        }
222
2.83k
        return res;
223
2.83k
      }
224
8.55M
    case CBOR_TYPE_ARRAY: {
225
8.55M
      cbor_item_t* res;
226
8.55M
      if (cbor_array_is_definite(item)) {
227
8.17M
        res = cbor_new_definite_array(cbor_array_size(item));
228
8.17M
      } else {
229
385k
        res = cbor_new_indefinite_array();
230
385k
      }
231
8.55M
      if (res == NULL) {
232
0
        return NULL;
233
0
      }
234
235
29.9M
      for (size_t i = 0; i < cbor_array_size(item); i++) {
236
21.3M
        cbor_item_t* entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
237
21.3M
        if (entry_copy == NULL) {
238
0
          cbor_decref(&res);
239
0
          return NULL;
240
0
        }
241
21.3M
        if (!cbor_array_push(res, entry_copy)) {
242
0
          cbor_decref(&entry_copy);
243
0
          cbor_decref(&res);
244
0
          return NULL;
245
0
        }
246
21.3M
        cbor_decref(&entry_copy);
247
21.3M
      }
248
8.55M
      return res;
249
8.55M
    }
250
46.1k
    case CBOR_TYPE_MAP: {
251
46.1k
      cbor_item_t* res;
252
46.1k
      if (cbor_map_is_definite(item)) {
253
43.7k
        res = cbor_new_definite_map(cbor_map_size(item));
254
43.7k
      } else {
255
2.37k
        res = cbor_new_indefinite_map();
256
2.37k
      }
257
46.1k
      if (res == NULL) {
258
0
        return NULL;
259
0
      }
260
261
46.1k
      struct cbor_pair* it = cbor_map_handle(item);
262
1.09M
      for (size_t i = 0; i < cbor_map_size(item); i++) {
263
1.04M
        cbor_item_t* key_copy = cbor_copy(it[i].key);
264
1.04M
        if (key_copy == NULL) {
265
0
          cbor_decref(&res);
266
0
          return NULL;
267
0
        }
268
1.04M
        cbor_item_t* value_copy = cbor_copy(it[i].value);
269
1.04M
        if (value_copy == NULL) {
270
0
          cbor_decref(&res);
271
0
          cbor_decref(&key_copy);
272
0
          return NULL;
273
0
        }
274
1.04M
        if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
275
1.04M
                                                  .value = value_copy})) {
276
0
          cbor_decref(&res);
277
0
          cbor_decref(&key_copy);
278
0
          cbor_decref(&value_copy);
279
0
          return NULL;
280
0
        }
281
1.04M
        cbor_decref(&key_copy);
282
1.04M
        cbor_decref(&value_copy);
283
1.04M
      }
284
46.1k
      return res;
285
46.1k
    }
286
240k
    case CBOR_TYPE_TAG: {
287
240k
      cbor_item_t* item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
288
240k
      if (item_copy == NULL) {
289
0
        return NULL;
290
0
      }
291
240k
      cbor_item_t* tag = cbor_build_tag(cbor_tag_value(item), item_copy);
292
240k
      cbor_decref(&item_copy);
293
240k
      return tag;
294
240k
    }
295
282k
    case CBOR_TYPE_FLOAT_CTRL:
296
282k
      return _cbor_copy_float_ctrl(item);
297
0
    default:  // LCOV_EXCL_START
298
0
      _CBOR_UNREACHABLE;
299
0
      return NULL;  // LCOV_EXCL_STOP
300
24.7M
  }
301
24.7M
}
302
303
0
cbor_item_t* cbor_copy_definite(cbor_item_t* item) {
304
0
  CBOR_ASSERT_VALID_TYPE(cbor_typeof(item));
305
0
  switch (cbor_typeof(item)) {
306
0
    case CBOR_TYPE_UINT:
307
0
    case CBOR_TYPE_NEGINT:
308
0
      return cbor_copy(item);
309
0
    case CBOR_TYPE_BYTESTRING:
310
0
      if (cbor_bytestring_is_definite(item)) {
311
0
        return cbor_copy(item);
312
0
      } else {
313
0
        size_t total_length = 0;
314
0
        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
315
0
          size_t chunk_length =
316
0
              cbor_bytestring_length(cbor_bytestring_chunks_handle(item)[i]);
317
0
          if (!_cbor_safe_to_add(total_length, chunk_length)) {
318
0
            return NULL;
319
0
          }
320
0
          total_length += chunk_length;
321
0
        }
322
323
0
        unsigned char* combined_data = _cbor_malloc(total_length);
324
0
        if (combined_data == NULL) {
325
0
          return NULL;
326
0
        }
327
328
0
        size_t offset = 0;
329
0
        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
330
0
          cbor_item_t* chunk = cbor_bytestring_chunks_handle(item)[i];
331
0
          memcpy(combined_data + offset, cbor_bytestring_handle(chunk),
332
0
                 cbor_bytestring_length(chunk));
333
0
          offset += cbor_bytestring_length(chunk);
334
0
        }
335
336
0
        cbor_item_t* res = cbor_new_definite_bytestring();
337
0
        cbor_bytestring_set_handle(res, combined_data, total_length);
338
0
        return res;
339
0
      }
340
0
    case CBOR_TYPE_STRING:
341
0
      if (cbor_string_is_definite(item)) {
342
0
        return cbor_copy(item);
343
0
      } else {
344
0
        size_t total_length = 0;
345
0
        for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
346
0
          size_t chunk_length =
347
0
              cbor_string_length(cbor_string_chunks_handle(item)[i]);
348
0
          if (!_cbor_safe_to_add(total_length, chunk_length)) {
349
0
            return NULL;
350
0
          }
351
0
          total_length += chunk_length;
352
0
        }
353
354
0
        unsigned char* combined_data = _cbor_malloc(total_length);
355
0
        if (combined_data == NULL) {
356
0
          return NULL;
357
0
        }
358
359
0
        size_t offset = 0;
360
0
        for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
361
0
          cbor_item_t* chunk = cbor_string_chunks_handle(item)[i];
362
0
          memcpy(combined_data + offset, cbor_string_handle(chunk),
363
0
                 cbor_string_length(chunk));
364
0
          offset += cbor_string_length(chunk);
365
0
        }
366
367
0
        cbor_item_t* res = cbor_new_definite_string();
368
0
        cbor_string_set_handle(res, combined_data, total_length);
369
0
        return res;
370
0
      }
371
0
    case CBOR_TYPE_ARRAY: {
372
0
      cbor_item_t* res = cbor_new_definite_array(cbor_array_size(item));
373
0
      if (res == NULL) {
374
0
        return NULL;
375
0
      }
376
377
0
      for (size_t i = 0; i < cbor_array_size(item); i++) {
378
0
        cbor_item_t* entry_copy =
379
0
            cbor_copy_definite(cbor_array_handle(item)[i]);
380
0
        if (entry_copy == NULL) {
381
0
          cbor_decref(&res);
382
0
          return NULL;
383
0
        }
384
        // Cannot fail since we have a definite array preallocated
385
        // cppcheck-suppress syntaxError
386
0
        const bool item_pushed _CBOR_UNUSED = cbor_array_push(res, entry_copy);
387
0
        CBOR_ASSERT(item_pushed);
388
0
        cbor_decref(&entry_copy);
389
0
      }
390
0
      return res;
391
0
    }
392
0
    case CBOR_TYPE_MAP: {
393
0
      cbor_item_t* res;
394
0
      res = cbor_new_definite_map(cbor_map_size(item));
395
0
      if (res == NULL) {
396
0
        return NULL;
397
0
      }
398
399
0
      struct cbor_pair* it = cbor_map_handle(item);
400
0
      for (size_t i = 0; i < cbor_map_size(item); i++) {
401
0
        cbor_item_t* key_copy = cbor_copy_definite(it[i].key);
402
0
        if (key_copy == NULL) {
403
0
          cbor_decref(&res);
404
0
          return NULL;
405
0
        }
406
0
        cbor_item_t* value_copy = cbor_copy_definite(it[i].value);
407
0
        if (value_copy == NULL) {
408
0
          cbor_decref(&res);
409
0
          cbor_decref(&key_copy);
410
0
          return NULL;
411
0
        }
412
        // Cannot fail since we have a definite map preallocated
413
        // cppcheck-suppress syntaxError
414
0
        const bool item_added _CBOR_UNUSED = cbor_map_add(
415
0
            res, (struct cbor_pair){.key = key_copy, .value = value_copy});
416
0
        CBOR_ASSERT(item_added);
417
0
        cbor_decref(&key_copy);
418
0
        cbor_decref(&value_copy);
419
0
      }
420
0
      return res;
421
0
    }
422
0
    case CBOR_TYPE_TAG: {
423
0
      cbor_item_t* item_copy =
424
0
          cbor_copy_definite(cbor_move(cbor_tag_item(item)));
425
0
      if (item_copy == NULL) {
426
0
        return NULL;
427
0
      }
428
0
      cbor_item_t* tag = cbor_build_tag(cbor_tag_value(item), item_copy);
429
0
      cbor_decref(&item_copy);
430
0
      return tag;
431
0
    }
432
0
    case CBOR_TYPE_FLOAT_CTRL:
433
0
      return cbor_copy(item);
434
0
    default:  // LCOV_EXCL_START
435
0
      _CBOR_UNREACHABLE;
436
0
      return NULL;  // LCOV_EXCL_STOP
437
0
  }
438
0
}
439
440
#if CBOR_PRETTY_PRINTER
441
442
#include <inttypes.h>
443
#include <locale.h>
444
#include <wchar.h>
445
446
#define __STDC_FORMAT_MACROS
447
448
14.3M
static int _pow(int b, int ex) {
449
14.3M
  if (ex == 0) return 1;
450
625k
  int res = b;
451
1.15M
  while (--ex > 0) res *= b;
452
625k
  return res;
453
14.3M
}
454
455
24.7M
static void _cbor_type_marquee(FILE* out, char* label, int indent) {
456
24.7M
  fprintf(out, "%*.*s[%s] ", indent, indent, " ", label);
457
24.7M
}
458
459
24.7M
static void _cbor_nested_describe(cbor_item_t* item, FILE* out, int indent) {
460
24.7M
  CBOR_ASSERT(cbor_typeof(item) >= CBOR_TYPE_UINT &&
461
24.7M
              cbor_typeof(item) <= CBOR_TYPE_FLOAT_CTRL);
462
24.7M
  const int indent_offset = 4;
463
24.7M
  switch (cbor_typeof(item)) {
464
11.3M
    case CBOR_TYPE_UINT: {
465
11.3M
      _cbor_type_marquee(out, "CBOR_TYPE_UINT", indent);
466
11.3M
      fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
467
11.3M
      fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
468
11.3M
      break;
469
0
    }
470
2.96M
    case CBOR_TYPE_NEGINT: {
471
2.96M
      _cbor_type_marquee(out, "CBOR_TYPE_NEGINT", indent);
472
2.96M
      fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
473
2.96M
      fprintf(out, "Value: -%" PRIu64 " - 1\n", cbor_get_int(item));
474
2.96M
      break;
475
0
    }
476
832k
    case CBOR_TYPE_BYTESTRING: {
477
832k
      _cbor_type_marquee(out, "CBOR_TYPE_BYTESTRING", indent);
478
832k
      if (cbor_bytestring_is_indefinite(item)) {
479
1.01k
        fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
480
1.01k
                cbor_bytestring_chunk_count(item));
481
746k
        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
482
745k
          _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
483
745k
                                indent + indent_offset);
484
831k
      } else {
485
831k
        const unsigned char* data = cbor_bytestring_handle(item);
486
831k
        fprintf(out, "Definite, Length: %zuB, Data:\n",
487
831k
                cbor_bytestring_length(item));
488
831k
        fprintf(out, "%*s", indent + indent_offset, " ");
489
3.24M
        for (size_t i = 0; i < cbor_bytestring_length(item); i++)
490
2.41M
          fprintf(out, "%02x", (int)(data[i] & 0xff));
491
831k
        fprintf(out, "\n");
492
831k
      }
493
832k
      break;
494
0
    }
495
450k
    case CBOR_TYPE_STRING: {
496
450k
      _cbor_type_marquee(out, "CBOR_TYPE_STRING", indent);
497
450k
      if (cbor_string_is_indefinite(item)) {
498
2.83k
        fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
499
2.83k
                cbor_string_chunk_count(item));
500
262k
        for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
501
259k
          _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
502
259k
                                indent + indent_offset);
503
447k
      } else {
504
447k
        fprintf(out, "Definite, Length: %zuB, Codepoints: %zu, Data:\n",
505
447k
                cbor_string_length(item), cbor_string_codepoint_count(item));
506
447k
        fprintf(out, "%*s", indent + indent_offset, " ");
507
        // Note: The string is not escaped, whitespace and control character
508
        // will be printed in verbatim and take effect.
509
447k
        fwrite(cbor_string_handle(item), sizeof(unsigned char),
510
447k
               cbor_string_length(item), out);
511
447k
        fprintf(out, "\n");
512
447k
      }
513
450k
      break;
514
0
    }
515
8.55M
    case CBOR_TYPE_ARRAY: {
516
8.55M
      _cbor_type_marquee(out, "CBOR_TYPE_ARRAY", indent);
517
8.55M
      if (cbor_array_is_definite(item)) {
518
8.17M
        fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_array_size(item));
519
8.17M
      } else {
520
385k
        fprintf(out, "Indefinite, Size: %zu, Contents:\n",
521
385k
                cbor_array_size(item));
522
385k
      }
523
524
29.9M
      for (size_t i = 0; i < cbor_array_size(item); i++)
525
21.3M
        _cbor_nested_describe(cbor_array_handle(item)[i], out,
526
21.3M
                              indent + indent_offset);
527
8.55M
      break;
528
0
    }
529
46.1k
    case CBOR_TYPE_MAP: {
530
46.1k
      _cbor_type_marquee(out, "CBOR_TYPE_MAP", indent);
531
46.1k
      if (cbor_map_is_definite(item)) {
532
43.7k
        fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_map_size(item));
533
43.7k
      } else {
534
2.37k
        fprintf(out, "Indefinite, Size: %zu, Contents:\n", cbor_map_size(item));
535
2.37k
      }
536
537
      // TODO: Label and group keys and values
538
1.09M
      for (size_t i = 0; i < cbor_map_size(item); i++) {
539
1.04M
        fprintf(out, "%*sMap entry %zu\n", indent + indent_offset, " ", i);
540
1.04M
        _cbor_nested_describe(cbor_map_handle(item)[i].key, out,
541
1.04M
                              indent + 2 * indent_offset);
542
1.04M
        _cbor_nested_describe(cbor_map_handle(item)[i].value, out,
543
1.04M
                              indent + 2 * indent_offset);
544
1.04M
      }
545
46.1k
      break;
546
0
    }
547
240k
    case CBOR_TYPE_TAG: {
548
240k
      _cbor_type_marquee(out, "CBOR_TYPE_TAG", indent);
549
240k
      fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
550
240k
      _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out,
551
240k
                            indent + indent_offset);
552
240k
      break;
553
0
    }
554
282k
    case CBOR_TYPE_FLOAT_CTRL: {
555
282k
      _cbor_type_marquee(out, "CBOR_TYPE_FLOAT_CTRL", indent);
556
282k
      if (cbor_float_ctrl_is_ctrl(item)) {
557
185k
        if (cbor_is_bool(item))
558
133k
          fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
559
52.4k
        else if (cbor_is_undef(item))
560
7.83k
          fprintf(out, "Undefined\n");
561
44.6k
        else if (cbor_is_null(item))
562
44.6k
          fprintf(out, "Null\n");
563
0
        else
564
0
          fprintf(out, "Simple value: %d\n", cbor_ctrl_value(item));
565
185k
      } else {
566
96.6k
        fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
567
96.6k
        fprintf(out, "Value: %lf\n", cbor_float_get_float(item));
568
96.6k
      }
569
282k
      break;
570
0
    }
571
24.7M
  }
572
24.7M
}
573
574
1.22k
void cbor_describe(cbor_item_t* item, FILE* out) {
575
1.22k
  _cbor_nested_describe(item, out, 0);
576
1.22k
}
577
578
#endif