Coverage Report

Created: 2025-07-18 06:26

/src/libcbor/src/cbor.c
Line
Count
Source (jump to first uncovered line)
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 "cbor.h"
9
#include "cbor/internal/builder_callbacks.h"
10
#include "cbor/internal/loaders.h"
11
12
#pragma clang diagnostic push
13
cbor_item_t *cbor_load(cbor_data source, size_t source_size,
14
38.9k
                       struct cbor_load_result *result) {
15
  /* Context stack */
16
38.9k
  static struct cbor_callbacks callbacks = {
17
38.9k
      .uint8 = &cbor_builder_uint8_callback,
18
38.9k
      .uint16 = &cbor_builder_uint16_callback,
19
38.9k
      .uint32 = &cbor_builder_uint32_callback,
20
38.9k
      .uint64 = &cbor_builder_uint64_callback,
21
22
38.9k
      .negint8 = &cbor_builder_negint8_callback,
23
38.9k
      .negint16 = &cbor_builder_negint16_callback,
24
38.9k
      .negint32 = &cbor_builder_negint32_callback,
25
38.9k
      .negint64 = &cbor_builder_negint64_callback,
26
27
38.9k
      .byte_string = &cbor_builder_byte_string_callback,
28
38.9k
      .byte_string_start = &cbor_builder_byte_string_start_callback,
29
30
38.9k
      .string = &cbor_builder_string_callback,
31
38.9k
      .string_start = &cbor_builder_string_start_callback,
32
33
38.9k
      .array_start = &cbor_builder_array_start_callback,
34
38.9k
      .indef_array_start = &cbor_builder_indef_array_start_callback,
35
36
38.9k
      .map_start = &cbor_builder_map_start_callback,
37
38.9k
      .indef_map_start = &cbor_builder_indef_map_start_callback,
38
39
38.9k
      .tag = &cbor_builder_tag_callback,
40
41
38.9k
      .null = &cbor_builder_null_callback,
42
38.9k
      .undefined = &cbor_builder_undefined_callback,
43
38.9k
      .boolean = &cbor_builder_boolean_callback,
44
38.9k
      .float2 = &cbor_builder_float2_callback,
45
38.9k
      .float4 = &cbor_builder_float4_callback,
46
38.9k
      .float8 = &cbor_builder_float8_callback,
47
38.9k
      .indef_break = &cbor_builder_indef_break_callback};
48
49
38.9k
  if (source_size == 0) {
50
0
    result->error.code = CBOR_ERR_NODATA;
51
0
    return NULL;
52
0
  }
53
38.9k
  struct _cbor_stack stack = _cbor_stack_init();
54
55
  /* Target for callbacks */
56
38.9k
  struct _cbor_decoder_context context = (struct _cbor_decoder_context){
57
38.9k
      .stack = &stack, .creation_failed = false, .syntax_error = false};
58
38.9k
  struct cbor_decoder_result decode_result;
59
38.9k
  *result =
60
38.9k
      (struct cbor_load_result){.read = 0, .error = {.code = CBOR_ERR_NONE}};
61
62
4.99M
  do {
63
4.99M
    if (source_size > result->read) { /* Check for overflows */
64
4.99M
      decode_result =
65
4.99M
          cbor_stream_decode(source + result->read, source_size - result->read,
66
4.99M
                             &callbacks, &context);
67
4.99M
    } else {
68
1.09k
      result->error = (struct cbor_error){.code = CBOR_ERR_NOTENOUGHDATA,
69
1.09k
                                          .position = result->read};
70
1.09k
      goto error;
71
1.09k
    }
72
73
4.99M
    switch (decode_result.status) {
74
4.99M
      case CBOR_DECODER_FINISHED:
75
        /* Everything OK */
76
4.99M
        {
77
4.99M
          result->read += decode_result.read;
78
4.99M
          break;
79
0
        }
80
870
      case CBOR_DECODER_NEDATA:
81
        /* Data length doesn't match MTB expectation */
82
870
        {
83
870
          result->error.code = CBOR_ERR_NOTENOUGHDATA;
84
870
          goto error;
85
0
        }
86
175
      case CBOR_DECODER_ERROR:
87
        /* Reserved/malformed item */
88
175
        {
89
175
          result->error.code = CBOR_ERR_MALFORMATED;
90
175
          goto error;
91
0
        }
92
4.99M
    }
93
94
4.99M
    if (context.creation_failed) {
95
      /* Most likely unsuccessful allocation - our callback has failed */
96
293
      result->error.code = CBOR_ERR_MEMERROR;
97
293
      goto error;
98
4.99M
    } else if (context.syntax_error) {
99
233
      result->error.code = CBOR_ERR_SYNTAXERROR;
100
233
      goto error;
101
233
    }
102
4.99M
  } while (stack.size > 0);
103
104
36.2k
  return context.root;
105
106
2.67k
error:
107
2.67k
  result->error.position = result->read;
108
  // debug_print("Failed with decoder error %d at %d\n", result->error.code,
109
  // result->error.position); cbor_describe(stack.top->item, stdout);
110
  /* Free the stack */
111
75.5k
  while (stack.size > 0) {
112
72.8k
    cbor_decref(&stack.top->item);
113
72.8k
    _cbor_stack_pop(&stack);
114
72.8k
  }
115
2.67k
  return NULL;
116
38.9k
}
117
118
0
static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
119
0
  cbor_item_t *res = NULL;
120
0
  switch (cbor_int_get_width(item)) {
121
0
    case CBOR_INT_8:
122
0
      res = cbor_build_uint8(cbor_get_uint8(item));
123
0
      break;
124
0
    case CBOR_INT_16:
125
0
      res = cbor_build_uint16(cbor_get_uint16(item));
126
0
      break;
127
0
    case CBOR_INT_32:
128
0
      res = cbor_build_uint32(cbor_get_uint32(item));
129
0
      break;
130
0
    case CBOR_INT_64:
131
0
      res = cbor_build_uint64(cbor_get_uint64(item));
132
0
      break;
133
0
  }
134
135
0
  if (negative) cbor_mark_negint(res);
136
137
0
  return res;
138
0
}
139
140
0
static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
141
  // cppcheck-suppress missingReturn
142
0
  switch (cbor_float_get_width(item)) {
143
0
    case CBOR_FLOAT_0:
144
0
      return cbor_build_ctrl(cbor_ctrl_value(item));
145
0
    case CBOR_FLOAT_16:
146
0
      return cbor_build_float2(cbor_float_get_float2(item));
147
0
    case CBOR_FLOAT_32:
148
0
      return cbor_build_float4(cbor_float_get_float4(item));
149
0
    case CBOR_FLOAT_64:
150
0
      return cbor_build_float8(cbor_float_get_float8(item));
151
0
  }
152
0
}
153
154
0
cbor_item_t *cbor_copy(cbor_item_t *item) {
155
  // cppcheck-suppress missingReturn
156
0
  switch (cbor_typeof(item)) {
157
0
    case CBOR_TYPE_UINT:
158
0
      return _cbor_copy_int(item, false);
159
0
    case CBOR_TYPE_NEGINT:
160
0
      return _cbor_copy_int(item, true);
161
0
    case CBOR_TYPE_BYTESTRING:
162
0
      if (cbor_bytestring_is_definite(item)) {
163
0
        return cbor_build_bytestring(cbor_bytestring_handle(item),
164
0
                                     cbor_bytestring_length(item));
165
0
      } else {
166
0
        cbor_item_t *res = cbor_new_indefinite_bytestring();
167
0
        if (res == NULL) {
168
0
          return NULL;
169
0
        }
170
171
0
        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
172
0
          cbor_item_t *chunk_copy =
173
0
              cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
174
0
          if (chunk_copy == NULL) {
175
0
            cbor_decref(&res);
176
0
            return NULL;
177
0
          }
178
0
          if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
179
0
            cbor_decref(&chunk_copy);
180
0
            cbor_decref(&res);
181
0
            return NULL;
182
0
          }
183
0
          cbor_decref(&chunk_copy);
184
0
        }
185
0
        return res;
186
0
      }
187
0
    case CBOR_TYPE_STRING:
188
0
      if (cbor_string_is_definite(item)) {
189
0
        return cbor_build_stringn((const char *)cbor_string_handle(item),
190
0
                                  cbor_string_length(item));
191
0
      } else {
192
0
        cbor_item_t *res = cbor_new_indefinite_string();
193
0
        if (res == NULL) {
194
0
          return NULL;
195
0
        }
196
197
0
        for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
198
0
          cbor_item_t *chunk_copy =
199
0
              cbor_copy(cbor_string_chunks_handle(item)[i]);
200
0
          if (chunk_copy == NULL) {
201
0
            cbor_decref(&res);
202
0
            return NULL;
203
0
          }
204
0
          if (!cbor_string_add_chunk(res, chunk_copy)) {
205
0
            cbor_decref(&chunk_copy);
206
0
            cbor_decref(&res);
207
0
            return NULL;
208
0
          }
209
0
          cbor_decref(&chunk_copy);
210
0
        }
211
0
        return res;
212
0
      }
213
0
    case CBOR_TYPE_ARRAY: {
214
0
      cbor_item_t *res;
215
0
      if (cbor_array_is_definite(item)) {
216
0
        res = cbor_new_definite_array(cbor_array_size(item));
217
0
      } else {
218
0
        res = cbor_new_indefinite_array();
219
0
      }
220
0
      if (res == NULL) {
221
0
        return NULL;
222
0
      }
223
224
0
      for (size_t i = 0; i < cbor_array_size(item); i++) {
225
0
        cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
226
0
        if (entry_copy == NULL) {
227
0
          cbor_decref(&res);
228
0
          return NULL;
229
0
        }
230
0
        if (!cbor_array_push(res, entry_copy)) {
231
0
          cbor_decref(&entry_copy);
232
0
          cbor_decref(&res);
233
0
          return NULL;
234
0
        }
235
0
        cbor_decref(&entry_copy);
236
0
      }
237
0
      return res;
238
0
    }
239
0
    case CBOR_TYPE_MAP: {
240
0
      cbor_item_t *res;
241
0
      if (cbor_map_is_definite(item)) {
242
0
        res = cbor_new_definite_map(cbor_map_size(item));
243
0
      } else {
244
0
        res = cbor_new_indefinite_map();
245
0
      }
246
0
      if (res == NULL) {
247
0
        return NULL;
248
0
      }
249
250
0
      struct cbor_pair *it = cbor_map_handle(item);
251
0
      for (size_t i = 0; i < cbor_map_size(item); i++) {
252
0
        cbor_item_t *key_copy = cbor_copy(it[i].key);
253
0
        if (key_copy == NULL) {
254
0
          cbor_decref(&res);
255
0
          return NULL;
256
0
        }
257
0
        cbor_item_t *value_copy = cbor_copy(it[i].value);
258
0
        if (value_copy == NULL) {
259
0
          cbor_decref(&res);
260
0
          cbor_decref(&key_copy);
261
0
          return NULL;
262
0
        }
263
0
        if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
264
0
                                                  .value = value_copy})) {
265
0
          cbor_decref(&res);
266
0
          cbor_decref(&key_copy);
267
0
          cbor_decref(&value_copy);
268
0
          return NULL;
269
0
        }
270
0
        cbor_decref(&key_copy);
271
0
        cbor_decref(&value_copy);
272
0
      }
273
0
      return res;
274
0
    }
275
0
    case CBOR_TYPE_TAG: {
276
0
      cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
277
0
      if (item_copy == NULL) {
278
0
        return NULL;
279
0
      }
280
0
      cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy);
281
0
      cbor_decref(&item_copy);
282
0
      return tag;
283
0
    }
284
0
    case CBOR_TYPE_FLOAT_CTRL:
285
0
      return _cbor_copy_float_ctrl(item);
286
0
  }
287
0
}
288
289
#if CBOR_PRETTY_PRINTER
290
291
#include <inttypes.h>
292
#include <locale.h>
293
#include <wchar.h>
294
295
#define __STDC_FORMAT_MACROS
296
297
0
static int _pow(int b, int ex) {
298
0
  if (ex == 0) return 1;
299
0
  int res = b;
300
0
  while (--ex > 0) res *= b;
301
0
  return res;
302
0
}
303
304
0
static void _cbor_type_marquee(FILE *out, char *label, int indent) {
305
0
  fprintf(out, "%*.*s[%s] ", indent, indent, " ", label);
306
0
}
307
308
0
static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
309
0
  const int indent_offset = 4;
310
0
  switch (cbor_typeof(item)) {
311
0
    case CBOR_TYPE_UINT: {
312
0
      _cbor_type_marquee(out, "CBOR_TYPE_UINT", indent);
313
0
      fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
314
0
      fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
315
0
      break;
316
0
    }
317
0
    case CBOR_TYPE_NEGINT: {
318
0
      _cbor_type_marquee(out, "CBOR_TYPE_NEGINT", indent);
319
0
      fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
320
0
      fprintf(out, "Value: -%" PRIu64 " - 1\n", cbor_get_int(item));
321
0
      break;
322
0
    }
323
0
    case CBOR_TYPE_BYTESTRING: {
324
0
      _cbor_type_marquee(out, "CBOR_TYPE_BYTESTRING", indent);
325
0
      if (cbor_bytestring_is_indefinite(item)) {
326
0
        fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
327
0
                cbor_bytestring_chunk_count(item));
328
0
        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
329
0
          _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
330
0
                                indent + indent_offset);
331
0
      } else {
332
0
        const unsigned char *data = cbor_bytestring_handle(item);
333
0
        fprintf(out, "Definite, Length: %zuB, Data:\n",
334
0
                cbor_bytestring_length(item));
335
0
        fprintf(out, "%*s", indent + indent_offset, " ");
336
0
        for (size_t i = 0; i < cbor_bytestring_length(item); i++)
337
0
          fprintf(out, "%02x", (int)(data[i] & 0xff));
338
0
        fprintf(out, "\n");
339
0
      }
340
0
      break;
341
0
    }
342
0
    case CBOR_TYPE_STRING: {
343
0
      _cbor_type_marquee(out, "CBOR_TYPE_STRING", indent);
344
0
      if (cbor_string_is_indefinite(item)) {
345
0
        fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
346
0
                cbor_string_chunk_count(item));
347
0
        for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
348
0
          _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
349
0
                                indent + indent_offset);
350
0
      } else {
351
0
        fprintf(out, "Definite, Length: %zuB, Codepoints: %zu, Data:\n",
352
0
                cbor_string_length(item), cbor_string_codepoint_count(item));
353
0
        fprintf(out, "%*s", indent + indent_offset, " ");
354
        // Note: The string is not escaped, whitespace and control character
355
        // will be printed in verbatim and take effect.
356
0
        fwrite(cbor_string_handle(item), sizeof(unsigned char),
357
0
               cbor_string_length(item), out);
358
0
        fprintf(out, "\n");
359
0
      }
360
0
      break;
361
0
    }
362
0
    case CBOR_TYPE_ARRAY: {
363
0
      _cbor_type_marquee(out, "CBOR_TYPE_ARRAY", indent);
364
0
      if (cbor_array_is_definite(item)) {
365
0
        fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_array_size(item));
366
0
      } else {
367
0
        fprintf(out, "Indefinite, Size: %zu, Contents:\n",
368
0
                cbor_array_size(item));
369
0
      }
370
371
0
      for (size_t i = 0; i < cbor_array_size(item); i++)
372
0
        _cbor_nested_describe(cbor_array_handle(item)[i], out,
373
0
                              indent + indent_offset);
374
0
      break;
375
0
    }
376
0
    case CBOR_TYPE_MAP: {
377
0
      _cbor_type_marquee(out, "CBOR_TYPE_MAP", indent);
378
0
      if (cbor_map_is_definite(item)) {
379
0
        fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_map_size(item));
380
0
      } else {
381
0
        fprintf(out, "Indefinite, Size: %zu, Contents:\n", cbor_map_size(item));
382
0
      }
383
384
      // TODO: Label and group keys and values
385
0
      for (size_t i = 0; i < cbor_map_size(item); i++) {
386
0
        fprintf(out, "%*sMap entry %zu\n", indent + indent_offset, " ", i);
387
0
        _cbor_nested_describe(cbor_map_handle(item)[i].key, out,
388
0
                              indent + 2 * indent_offset);
389
0
        _cbor_nested_describe(cbor_map_handle(item)[i].value, out,
390
0
                              indent + 2 * indent_offset);
391
0
      }
392
0
      break;
393
0
    }
394
0
    case CBOR_TYPE_TAG: {
395
0
      _cbor_type_marquee(out, "CBOR_TYPE_TAG", indent);
396
0
      fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
397
0
      _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out,
398
0
                            indent + indent_offset);
399
0
      break;
400
0
    }
401
0
    case CBOR_TYPE_FLOAT_CTRL: {
402
0
      _cbor_type_marquee(out, "CBOR_TYPE_FLOAT_CTRL", indent);
403
0
      if (cbor_float_ctrl_is_ctrl(item)) {
404
0
        if (cbor_is_bool(item))
405
0
          fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
406
0
        else if (cbor_is_undef(item))
407
0
          fprintf(out, "Undefined\n");
408
0
        else if (cbor_is_null(item))
409
0
          fprintf(out, "Null\n");
410
0
        else
411
0
          fprintf(out, "Simple value: %d\n", cbor_ctrl_value(item));
412
0
      } else {
413
0
        fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
414
0
        fprintf(out, "Value: %lf\n", cbor_float_get_float(item));
415
0
      }
416
0
      break;
417
0
    }
418
0
  }
419
0
}
420
421
0
void cbor_describe(cbor_item_t *item, FILE *out) {
422
0
  _cbor_nested_describe(item, out, 0);
423
0
}
424
425
#endif