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