xref: /freebsd-src/contrib/libcbor/src/cbor.c (revision abd872540f24cfc7dbd1ea29b6918c7082a22108)
110ff414cSEd Maste /*
210ff414cSEd Maste  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
310ff414cSEd Maste  *
410ff414cSEd Maste  * libcbor is free software; you can redistribute it and/or modify
510ff414cSEd Maste  * it under the terms of the MIT license. See LICENSE for details.
610ff414cSEd Maste  */
710ff414cSEd Maste 
810ff414cSEd Maste #include "cbor.h"
910ff414cSEd Maste #include "cbor/internal/builder_callbacks.h"
1010ff414cSEd Maste #include "cbor/internal/loaders.h"
1110ff414cSEd Maste 
12*abd87254SEd Maste #pragma clang diagnostic push
cbor_load(cbor_data source,size_t source_size,struct cbor_load_result * result)1310ff414cSEd Maste cbor_item_t *cbor_load(cbor_data source, size_t source_size,
1410ff414cSEd Maste                        struct cbor_load_result *result) {
1510ff414cSEd Maste   /* Context stack */
1610ff414cSEd Maste   static struct cbor_callbacks callbacks = {
1710ff414cSEd Maste       .uint8 = &cbor_builder_uint8_callback,
1810ff414cSEd Maste       .uint16 = &cbor_builder_uint16_callback,
1910ff414cSEd Maste       .uint32 = &cbor_builder_uint32_callback,
2010ff414cSEd Maste       .uint64 = &cbor_builder_uint64_callback,
2110ff414cSEd Maste 
2210ff414cSEd Maste       .negint8 = &cbor_builder_negint8_callback,
2310ff414cSEd Maste       .negint16 = &cbor_builder_negint16_callback,
2410ff414cSEd Maste       .negint32 = &cbor_builder_negint32_callback,
2510ff414cSEd Maste       .negint64 = &cbor_builder_negint64_callback,
2610ff414cSEd Maste 
2710ff414cSEd Maste       .byte_string = &cbor_builder_byte_string_callback,
2810ff414cSEd Maste       .byte_string_start = &cbor_builder_byte_string_start_callback,
2910ff414cSEd Maste 
3010ff414cSEd Maste       .string = &cbor_builder_string_callback,
3110ff414cSEd Maste       .string_start = &cbor_builder_string_start_callback,
3210ff414cSEd Maste 
3310ff414cSEd Maste       .array_start = &cbor_builder_array_start_callback,
3410ff414cSEd Maste       .indef_array_start = &cbor_builder_indef_array_start_callback,
3510ff414cSEd Maste 
3610ff414cSEd Maste       .map_start = &cbor_builder_map_start_callback,
3710ff414cSEd Maste       .indef_map_start = &cbor_builder_indef_map_start_callback,
3810ff414cSEd Maste 
3910ff414cSEd Maste       .tag = &cbor_builder_tag_callback,
4010ff414cSEd Maste 
4110ff414cSEd Maste       .null = &cbor_builder_null_callback,
4210ff414cSEd Maste       .undefined = &cbor_builder_undefined_callback,
4310ff414cSEd Maste       .boolean = &cbor_builder_boolean_callback,
4410ff414cSEd Maste       .float2 = &cbor_builder_float2_callback,
4510ff414cSEd Maste       .float4 = &cbor_builder_float4_callback,
4610ff414cSEd Maste       .float8 = &cbor_builder_float8_callback,
4710ff414cSEd Maste       .indef_break = &cbor_builder_indef_break_callback};
4810ff414cSEd Maste 
4910ff414cSEd Maste   if (source_size == 0) {
5010ff414cSEd Maste     result->error.code = CBOR_ERR_NODATA;
5110ff414cSEd Maste     return NULL;
5210ff414cSEd Maste   }
5310ff414cSEd Maste   struct _cbor_stack stack = _cbor_stack_init();
5410ff414cSEd Maste 
5510ff414cSEd Maste   /* Target for callbacks */
5610ff414cSEd Maste   struct _cbor_decoder_context context = (struct _cbor_decoder_context){
5710ff414cSEd Maste       .stack = &stack, .creation_failed = false, .syntax_error = false};
5810ff414cSEd Maste   struct cbor_decoder_result decode_result;
5910ff414cSEd Maste   *result =
6010ff414cSEd Maste       (struct cbor_load_result){.read = 0, .error = {.code = CBOR_ERR_NONE}};
6110ff414cSEd Maste 
6210ff414cSEd Maste   do {
6310ff414cSEd Maste     if (source_size > result->read) { /* Check for overflows */
6410ff414cSEd Maste       decode_result =
6510ff414cSEd Maste           cbor_stream_decode(source + result->read, source_size - result->read,
6610ff414cSEd Maste                              &callbacks, &context);
6710ff414cSEd Maste     } else {
6810ff414cSEd Maste       result->error = (struct cbor_error){.code = CBOR_ERR_NOTENOUGHDATA,
6910ff414cSEd Maste                                           .position = result->read};
7010ff414cSEd Maste       goto error;
7110ff414cSEd Maste     }
7210ff414cSEd Maste 
7310ff414cSEd Maste     switch (decode_result.status) {
7410ff414cSEd Maste       case CBOR_DECODER_FINISHED:
7510ff414cSEd Maste         /* Everything OK */
7610ff414cSEd Maste         {
7710ff414cSEd Maste           result->read += decode_result.read;
7810ff414cSEd Maste           break;
7910ff414cSEd Maste         }
8010ff414cSEd Maste       case CBOR_DECODER_NEDATA:
8110ff414cSEd Maste         /* Data length doesn't match MTB expectation */
8210ff414cSEd Maste         {
8310ff414cSEd Maste           result->error.code = CBOR_ERR_NOTENOUGHDATA;
8410ff414cSEd Maste           goto error;
8510ff414cSEd Maste         }
8610ff414cSEd Maste       case CBOR_DECODER_ERROR:
875d3e7166SEd Maste         /* Reserved/malformed item */
8810ff414cSEd Maste         {
8910ff414cSEd Maste           result->error.code = CBOR_ERR_MALFORMATED;
9010ff414cSEd Maste           goto error;
9110ff414cSEd Maste         }
9210ff414cSEd Maste     }
9310ff414cSEd Maste 
9410ff414cSEd Maste     if (context.creation_failed) {
9510ff414cSEd Maste       /* Most likely unsuccessful allocation - our callback has failed */
9610ff414cSEd Maste       result->error.code = CBOR_ERR_MEMERROR;
9710ff414cSEd Maste       goto error;
9810ff414cSEd Maste     } else if (context.syntax_error) {
9910ff414cSEd Maste       result->error.code = CBOR_ERR_SYNTAXERROR;
10010ff414cSEd Maste       goto error;
10110ff414cSEd Maste     }
10210ff414cSEd Maste   } while (stack.size > 0);
10310ff414cSEd Maste 
1045d3e7166SEd Maste   return context.root;
10510ff414cSEd Maste 
10610ff414cSEd Maste error:
10710ff414cSEd Maste   result->error.position = result->read;
10810ff414cSEd Maste   // debug_print("Failed with decoder error %d at %d\n", result->error.code,
10910ff414cSEd Maste   // result->error.position); cbor_describe(stack.top->item, stdout);
11010ff414cSEd Maste   /* Free the stack */
11110ff414cSEd Maste   while (stack.size > 0) {
11210ff414cSEd Maste     cbor_decref(&stack.top->item);
11310ff414cSEd Maste     _cbor_stack_pop(&stack);
11410ff414cSEd Maste   }
11510ff414cSEd Maste   return NULL;
11610ff414cSEd Maste }
11710ff414cSEd Maste 
_cbor_copy_int(cbor_item_t * item,bool negative)11810ff414cSEd Maste static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
11910ff414cSEd Maste   cbor_item_t *res;
12010ff414cSEd Maste   switch (cbor_int_get_width(item)) {
12110ff414cSEd Maste     case CBOR_INT_8:
12210ff414cSEd Maste       res = cbor_build_uint8(cbor_get_uint8(item));
12310ff414cSEd Maste       break;
12410ff414cSEd Maste     case CBOR_INT_16:
12510ff414cSEd Maste       res = cbor_build_uint16(cbor_get_uint16(item));
12610ff414cSEd Maste       break;
12710ff414cSEd Maste     case CBOR_INT_32:
12810ff414cSEd Maste       res = cbor_build_uint32(cbor_get_uint32(item));
12910ff414cSEd Maste       break;
13010ff414cSEd Maste     case CBOR_INT_64:
13110ff414cSEd Maste       res = cbor_build_uint64(cbor_get_uint64(item));
13210ff414cSEd Maste       break;
13310ff414cSEd Maste   }
13410ff414cSEd Maste 
13510ff414cSEd Maste   if (negative) cbor_mark_negint(res);
13610ff414cSEd Maste 
13710ff414cSEd Maste   return res;
13810ff414cSEd Maste }
13910ff414cSEd Maste 
_cbor_copy_float_ctrl(cbor_item_t * item)14010ff414cSEd Maste static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
1415d3e7166SEd Maste   // cppcheck-suppress missingReturn
14210ff414cSEd Maste   switch (cbor_float_get_width(item)) {
14310ff414cSEd Maste     case CBOR_FLOAT_0:
14410ff414cSEd Maste       return cbor_build_ctrl(cbor_ctrl_value(item));
14510ff414cSEd Maste     case CBOR_FLOAT_16:
14610ff414cSEd Maste       return cbor_build_float2(cbor_float_get_float2(item));
14710ff414cSEd Maste     case CBOR_FLOAT_32:
14810ff414cSEd Maste       return cbor_build_float4(cbor_float_get_float4(item));
14910ff414cSEd Maste     case CBOR_FLOAT_64:
15010ff414cSEd Maste       return cbor_build_float8(cbor_float_get_float8(item));
15110ff414cSEd Maste   }
15210ff414cSEd Maste }
15310ff414cSEd Maste 
cbor_copy(cbor_item_t * item)15410ff414cSEd Maste cbor_item_t *cbor_copy(cbor_item_t *item) {
1555d3e7166SEd Maste   // cppcheck-suppress missingReturn
15610ff414cSEd Maste   switch (cbor_typeof(item)) {
15710ff414cSEd Maste     case CBOR_TYPE_UINT:
15810ff414cSEd Maste       return _cbor_copy_int(item, false);
15910ff414cSEd Maste     case CBOR_TYPE_NEGINT:
16010ff414cSEd Maste       return _cbor_copy_int(item, true);
16110ff414cSEd Maste     case CBOR_TYPE_BYTESTRING:
16210ff414cSEd Maste       if (cbor_bytestring_is_definite(item)) {
16310ff414cSEd Maste         return cbor_build_bytestring(cbor_bytestring_handle(item),
16410ff414cSEd Maste                                      cbor_bytestring_length(item));
16510ff414cSEd Maste       } else {
16610ff414cSEd Maste         cbor_item_t *res = cbor_new_indefinite_bytestring();
1675d3e7166SEd Maste         if (res == NULL) {
1685d3e7166SEd Maste           return NULL;
1695d3e7166SEd Maste         }
1705d3e7166SEd Maste 
1715d3e7166SEd Maste         for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
1725d3e7166SEd Maste           cbor_item_t *chunk_copy =
1735d3e7166SEd Maste               cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
1745d3e7166SEd Maste           if (chunk_copy == NULL) {
1755d3e7166SEd Maste             cbor_decref(&res);
1765d3e7166SEd Maste             return NULL;
1775d3e7166SEd Maste           }
1785d3e7166SEd Maste           if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
1795d3e7166SEd Maste             cbor_decref(&chunk_copy);
1805d3e7166SEd Maste             cbor_decref(&res);
1815d3e7166SEd Maste             return NULL;
1825d3e7166SEd Maste           }
1835d3e7166SEd Maste           cbor_decref(&chunk_copy);
1845d3e7166SEd Maste         }
18510ff414cSEd Maste         return res;
18610ff414cSEd Maste       }
18710ff414cSEd Maste     case CBOR_TYPE_STRING:
18810ff414cSEd Maste       if (cbor_string_is_definite(item)) {
18910ff414cSEd Maste         return cbor_build_stringn((const char *)cbor_string_handle(item),
19010ff414cSEd Maste                                   cbor_string_length(item));
19110ff414cSEd Maste       } else {
19210ff414cSEd Maste         cbor_item_t *res = cbor_new_indefinite_string();
1935d3e7166SEd Maste         if (res == NULL) {
1945d3e7166SEd Maste           return NULL;
1955d3e7166SEd Maste         }
1965d3e7166SEd Maste 
1975d3e7166SEd Maste         for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
1985d3e7166SEd Maste           cbor_item_t *chunk_copy =
1995d3e7166SEd Maste               cbor_copy(cbor_string_chunks_handle(item)[i]);
2005d3e7166SEd Maste           if (chunk_copy == NULL) {
2015d3e7166SEd Maste             cbor_decref(&res);
2025d3e7166SEd Maste             return NULL;
2035d3e7166SEd Maste           }
2045d3e7166SEd Maste           if (!cbor_string_add_chunk(res, chunk_copy)) {
2055d3e7166SEd Maste             cbor_decref(&chunk_copy);
2065d3e7166SEd Maste             cbor_decref(&res);
2075d3e7166SEd Maste             return NULL;
2085d3e7166SEd Maste           }
2095d3e7166SEd Maste           cbor_decref(&chunk_copy);
2105d3e7166SEd Maste         }
21110ff414cSEd Maste         return res;
21210ff414cSEd Maste       }
21310ff414cSEd Maste     case CBOR_TYPE_ARRAY: {
21410ff414cSEd Maste       cbor_item_t *res;
2155d3e7166SEd Maste       if (cbor_array_is_definite(item)) {
21610ff414cSEd Maste         res = cbor_new_definite_array(cbor_array_size(item));
2175d3e7166SEd Maste       } else {
21810ff414cSEd Maste         res = cbor_new_indefinite_array();
2195d3e7166SEd Maste       }
2205d3e7166SEd Maste       if (res == NULL) {
2215d3e7166SEd Maste         return NULL;
2225d3e7166SEd Maste       }
22310ff414cSEd Maste 
2245d3e7166SEd Maste       for (size_t i = 0; i < cbor_array_size(item); i++) {
2255d3e7166SEd Maste         cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
2265d3e7166SEd Maste         if (entry_copy == NULL) {
2275d3e7166SEd Maste           cbor_decref(&res);
2285d3e7166SEd Maste           return NULL;
2295d3e7166SEd Maste         }
2305d3e7166SEd Maste         if (!cbor_array_push(res, entry_copy)) {
2315d3e7166SEd Maste           cbor_decref(&entry_copy);
2325d3e7166SEd Maste           cbor_decref(&res);
2335d3e7166SEd Maste           return NULL;
2345d3e7166SEd Maste         }
2355d3e7166SEd Maste         cbor_decref(&entry_copy);
2365d3e7166SEd Maste       }
23710ff414cSEd Maste       return res;
23810ff414cSEd Maste     }
23910ff414cSEd Maste     case CBOR_TYPE_MAP: {
24010ff414cSEd Maste       cbor_item_t *res;
2415d3e7166SEd Maste       if (cbor_map_is_definite(item)) {
24210ff414cSEd Maste         res = cbor_new_definite_map(cbor_map_size(item));
2435d3e7166SEd Maste       } else {
24410ff414cSEd Maste         res = cbor_new_indefinite_map();
2455d3e7166SEd Maste       }
2465d3e7166SEd Maste       if (res == NULL) {
2475d3e7166SEd Maste         return NULL;
2485d3e7166SEd Maste       }
24910ff414cSEd Maste 
25010ff414cSEd Maste       struct cbor_pair *it = cbor_map_handle(item);
2515d3e7166SEd Maste       for (size_t i = 0; i < cbor_map_size(item); i++) {
2525d3e7166SEd Maste         cbor_item_t *key_copy = cbor_copy(it[i].key);
2535d3e7166SEd Maste         if (key_copy == NULL) {
2545d3e7166SEd Maste           cbor_decref(&res);
2555d3e7166SEd Maste           return NULL;
2565d3e7166SEd Maste         }
2575d3e7166SEd Maste         cbor_item_t *value_copy = cbor_copy(it[i].value);
2585d3e7166SEd Maste         if (value_copy == NULL) {
2595d3e7166SEd Maste           cbor_decref(&res);
2605d3e7166SEd Maste           cbor_decref(&key_copy);
2615d3e7166SEd Maste           return NULL;
2625d3e7166SEd Maste         }
2635d3e7166SEd Maste         if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
2645d3e7166SEd Maste                                                   .value = value_copy})) {
2655d3e7166SEd Maste           cbor_decref(&res);
2665d3e7166SEd Maste           cbor_decref(&key_copy);
2675d3e7166SEd Maste           cbor_decref(&value_copy);
2685d3e7166SEd Maste           return NULL;
2695d3e7166SEd Maste         }
2705d3e7166SEd Maste         cbor_decref(&key_copy);
2715d3e7166SEd Maste         cbor_decref(&value_copy);
2725d3e7166SEd Maste       }
27310ff414cSEd Maste       return res;
27410ff414cSEd Maste     }
2755d3e7166SEd Maste     case CBOR_TYPE_TAG: {
2765d3e7166SEd Maste       cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
2775d3e7166SEd Maste       if (item_copy == NULL) {
2785d3e7166SEd Maste         return NULL;
2795d3e7166SEd Maste       }
2805d3e7166SEd Maste       cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy);
2815d3e7166SEd Maste       cbor_decref(&item_copy);
2825d3e7166SEd Maste       return tag;
2835d3e7166SEd Maste     }
28410ff414cSEd Maste     case CBOR_TYPE_FLOAT_CTRL:
28510ff414cSEd Maste       return _cbor_copy_float_ctrl(item);
28610ff414cSEd Maste   }
28710ff414cSEd Maste }
28810ff414cSEd Maste 
28910ff414cSEd Maste #if CBOR_PRETTY_PRINTER
29010ff414cSEd Maste 
29110ff414cSEd Maste #include <inttypes.h>
29210ff414cSEd Maste #include <locale.h>
29310ff414cSEd Maste #include <wchar.h>
29410ff414cSEd Maste 
29510ff414cSEd Maste #define __STDC_FORMAT_MACROS
29610ff414cSEd Maste 
_pow(int b,int ex)29710ff414cSEd Maste static int _pow(int b, int ex) {
29810ff414cSEd Maste   if (ex == 0) return 1;
29910ff414cSEd Maste   int res = b;
30010ff414cSEd Maste   while (--ex > 0) res *= b;
30110ff414cSEd Maste   return res;
30210ff414cSEd Maste }
30310ff414cSEd Maste 
_cbor_type_marquee(FILE * out,char * label,int indent)304*abd87254SEd Maste static void _cbor_type_marquee(FILE *out, char *label, int indent) {
305*abd87254SEd Maste   fprintf(out, "%*.*s[%s] ", indent, indent, " ", label);
306*abd87254SEd Maste }
307*abd87254SEd Maste 
_cbor_nested_describe(cbor_item_t * item,FILE * out,int indent)30810ff414cSEd Maste static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
309*abd87254SEd Maste   const int indent_offset = 4;
31010ff414cSEd Maste   switch (cbor_typeof(item)) {
31110ff414cSEd Maste     case CBOR_TYPE_UINT: {
312*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_UINT", indent);
31310ff414cSEd Maste       fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
31410ff414cSEd Maste       fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
31510ff414cSEd Maste       break;
3165d3e7166SEd Maste     }
31710ff414cSEd Maste     case CBOR_TYPE_NEGINT: {
318*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_NEGINT", indent);
31910ff414cSEd Maste       fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
32010ff414cSEd Maste       fprintf(out, "Value: -%" PRIu64 " - 1\n", cbor_get_int(item));
32110ff414cSEd Maste       break;
3225d3e7166SEd Maste     }
32310ff414cSEd Maste     case CBOR_TYPE_BYTESTRING: {
324*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_BYTESTRING", indent);
32510ff414cSEd Maste       if (cbor_bytestring_is_indefinite(item)) {
326*abd87254SEd Maste         fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
32710ff414cSEd Maste                 cbor_bytestring_chunk_count(item));
32810ff414cSEd Maste         for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
32910ff414cSEd Maste           _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
330*abd87254SEd Maste                                 indent + indent_offset);
33110ff414cSEd Maste       } else {
332*abd87254SEd Maste         const unsigned char *data = cbor_bytestring_handle(item);
333*abd87254SEd Maste         fprintf(out, "Definite, Length: %zuB, Data:\n",
334*abd87254SEd Maste                 cbor_bytestring_length(item));
335*abd87254SEd Maste         fprintf(out, "%*s", indent + indent_offset, " ");
336*abd87254SEd Maste         for (size_t i = 0; i < cbor_bytestring_length(item); i++)
337*abd87254SEd Maste           fprintf(out, "%02x", (int)(data[i] & 0xff));
338*abd87254SEd Maste         fprintf(out, "\n");
33910ff414cSEd Maste       }
34010ff414cSEd Maste       break;
3415d3e7166SEd Maste     }
34210ff414cSEd Maste     case CBOR_TYPE_STRING: {
343*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_STRING", indent);
34410ff414cSEd Maste       if (cbor_string_is_indefinite(item)) {
345*abd87254SEd Maste         fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
34610ff414cSEd Maste                 cbor_string_chunk_count(item));
34710ff414cSEd Maste         for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
34810ff414cSEd Maste           _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
349*abd87254SEd Maste                                 indent + indent_offset);
35010ff414cSEd Maste       } else {
351*abd87254SEd Maste         fprintf(out, "Definite, Length: %zuB, Codepoints: %zu, Data:\n",
35210ff414cSEd Maste                 cbor_string_length(item), cbor_string_codepoint_count(item));
353*abd87254SEd Maste         fprintf(out, "%*s", indent + indent_offset, " ");
354*abd87254SEd Maste         // Note: The string is not escaped, whitespace and control character
355*abd87254SEd Maste         // will be printed in verbatim and take effect.
356*abd87254SEd Maste         fwrite(cbor_string_handle(item), sizeof(unsigned char),
357*abd87254SEd Maste                cbor_string_length(item), out);
35810ff414cSEd Maste         fprintf(out, "\n");
35910ff414cSEd Maste       }
36010ff414cSEd Maste       break;
3615d3e7166SEd Maste     }
36210ff414cSEd Maste     case CBOR_TYPE_ARRAY: {
363*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_ARRAY", indent);
36410ff414cSEd Maste       if (cbor_array_is_definite(item)) {
365*abd87254SEd Maste         fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_array_size(item));
36610ff414cSEd Maste       } else {
367*abd87254SEd Maste         fprintf(out, "Indefinite, Size: %zu, Contents:\n",
368*abd87254SEd Maste                 cbor_array_size(item));
36910ff414cSEd Maste       }
37010ff414cSEd Maste 
37110ff414cSEd Maste       for (size_t i = 0; i < cbor_array_size(item); i++)
372*abd87254SEd Maste         _cbor_nested_describe(cbor_array_handle(item)[i], out,
373*abd87254SEd Maste                               indent + indent_offset);
37410ff414cSEd Maste       break;
3755d3e7166SEd Maste     }
37610ff414cSEd Maste     case CBOR_TYPE_MAP: {
377*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_MAP", indent);
37810ff414cSEd Maste       if (cbor_map_is_definite(item)) {
379*abd87254SEd Maste         fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_map_size(item));
38010ff414cSEd Maste       } else {
381*abd87254SEd Maste         fprintf(out, "Indefinite, Size: %zu, Contents:\n", cbor_map_size(item));
38210ff414cSEd Maste       }
38310ff414cSEd Maste 
384*abd87254SEd Maste       // TODO: Label and group keys and values
38510ff414cSEd Maste       for (size_t i = 0; i < cbor_map_size(item); i++) {
386*abd87254SEd Maste         fprintf(out, "%*sMap entry %zu\n", indent + indent_offset, " ", i);
387*abd87254SEd Maste         _cbor_nested_describe(cbor_map_handle(item)[i].key, out,
388*abd87254SEd Maste                               indent + 2 * indent_offset);
389*abd87254SEd Maste         _cbor_nested_describe(cbor_map_handle(item)[i].value, out,
390*abd87254SEd Maste                               indent + 2 * indent_offset);
39110ff414cSEd Maste       }
39210ff414cSEd Maste       break;
3935d3e7166SEd Maste     }
39410ff414cSEd Maste     case CBOR_TYPE_TAG: {
395*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_TAG", indent);
39610ff414cSEd Maste       fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
397*abd87254SEd Maste       _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out,
398*abd87254SEd Maste                             indent + indent_offset);
39910ff414cSEd Maste       break;
4005d3e7166SEd Maste     }
40110ff414cSEd Maste     case CBOR_TYPE_FLOAT_CTRL: {
402*abd87254SEd Maste       _cbor_type_marquee(out, "CBOR_TYPE_FLOAT_CTRL", indent);
40310ff414cSEd Maste       if (cbor_float_ctrl_is_ctrl(item)) {
40410ff414cSEd Maste         if (cbor_is_bool(item))
40510ff414cSEd Maste           fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
40610ff414cSEd Maste         else if (cbor_is_undef(item))
40710ff414cSEd Maste           fprintf(out, "Undefined\n");
40810ff414cSEd Maste         else if (cbor_is_null(item))
40910ff414cSEd Maste           fprintf(out, "Null\n");
41010ff414cSEd Maste         else
411*abd87254SEd Maste           fprintf(out, "Simple value: %d\n", cbor_ctrl_value(item));
41210ff414cSEd Maste       } else {
41310ff414cSEd Maste         fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
414*abd87254SEd Maste         fprintf(out, "Value: %lf\n", cbor_float_get_float(item));
41510ff414cSEd Maste       }
41610ff414cSEd Maste       break;
4175d3e7166SEd Maste     }
41810ff414cSEd Maste   }
41910ff414cSEd Maste }
42010ff414cSEd Maste 
cbor_describe(cbor_item_t * item,FILE * out)42110ff414cSEd Maste void cbor_describe(cbor_item_t *item, FILE *out) {
42210ff414cSEd Maste   _cbor_nested_describe(item, out, 0);
42310ff414cSEd Maste }
42410ff414cSEd Maste 
42510ff414cSEd Maste #endif
426