xref: /openbsd-src/lib/libcbor/src/cbor.c (revision 4dcc46c4d04180142eda526ce521dfb137776d05)
1da0d961cSdjm /*
2d3425be1Sdjm  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3da0d961cSdjm  *
4da0d961cSdjm  * libcbor is free software; you can redistribute it and/or modify
5da0d961cSdjm  * it under the terms of the MIT license. See LICENSE for details.
6da0d961cSdjm  */
7da0d961cSdjm 
8da0d961cSdjm #include "cbor.h"
9da0d961cSdjm #include "cbor/internal/builder_callbacks.h"
10da0d961cSdjm #include "cbor/internal/loaders.h"
11da0d961cSdjm 
cbor_load(cbor_data source,size_t source_size,struct cbor_load_result * result)129e5c2ddcSdjm cbor_item_t *cbor_load(cbor_data source, size_t source_size,
139e5c2ddcSdjm                        struct cbor_load_result *result) {
14da0d961cSdjm   /* Context stack */
15da0d961cSdjm   static struct cbor_callbacks callbacks = {
16da0d961cSdjm       .uint8 = &cbor_builder_uint8_callback,
17da0d961cSdjm       .uint16 = &cbor_builder_uint16_callback,
18da0d961cSdjm       .uint32 = &cbor_builder_uint32_callback,
19da0d961cSdjm       .uint64 = &cbor_builder_uint64_callback,
20da0d961cSdjm 
21da0d961cSdjm       .negint8 = &cbor_builder_negint8_callback,
22da0d961cSdjm       .negint16 = &cbor_builder_negint16_callback,
23da0d961cSdjm       .negint32 = &cbor_builder_negint32_callback,
24da0d961cSdjm       .negint64 = &cbor_builder_negint64_callback,
25da0d961cSdjm 
26da0d961cSdjm       .byte_string = &cbor_builder_byte_string_callback,
27da0d961cSdjm       .byte_string_start = &cbor_builder_byte_string_start_callback,
28da0d961cSdjm 
29da0d961cSdjm       .string = &cbor_builder_string_callback,
30da0d961cSdjm       .string_start = &cbor_builder_string_start_callback,
31da0d961cSdjm 
32da0d961cSdjm       .array_start = &cbor_builder_array_start_callback,
33da0d961cSdjm       .indef_array_start = &cbor_builder_indef_array_start_callback,
34da0d961cSdjm 
35da0d961cSdjm       .map_start = &cbor_builder_map_start_callback,
36da0d961cSdjm       .indef_map_start = &cbor_builder_indef_map_start_callback,
37da0d961cSdjm 
38da0d961cSdjm       .tag = &cbor_builder_tag_callback,
39da0d961cSdjm 
40da0d961cSdjm       .null = &cbor_builder_null_callback,
41da0d961cSdjm       .undefined = &cbor_builder_undefined_callback,
42da0d961cSdjm       .boolean = &cbor_builder_boolean_callback,
43da0d961cSdjm       .float2 = &cbor_builder_float2_callback,
44da0d961cSdjm       .float4 = &cbor_builder_float4_callback,
45da0d961cSdjm       .float8 = &cbor_builder_float8_callback,
469e5c2ddcSdjm       .indef_break = &cbor_builder_indef_break_callback};
47da0d961cSdjm 
48da0d961cSdjm   if (source_size == 0) {
49da0d961cSdjm     result->error.code = CBOR_ERR_NODATA;
50da0d961cSdjm     return NULL;
51da0d961cSdjm   }
52da0d961cSdjm   struct _cbor_stack stack = _cbor_stack_init();
53da0d961cSdjm 
54da0d961cSdjm   /* Target for callbacks */
55da0d961cSdjm   struct _cbor_decoder_context context = (struct _cbor_decoder_context){
569e5c2ddcSdjm       .stack = &stack, .creation_failed = false, .syntax_error = false};
57da0d961cSdjm   struct cbor_decoder_result decode_result;
589e5c2ddcSdjm   *result =
599e5c2ddcSdjm       (struct cbor_load_result){.read = 0, .error = {.code = CBOR_ERR_NONE}};
60da0d961cSdjm 
61da0d961cSdjm   do {
62da0d961cSdjm     if (source_size > result->read) { /* Check for overflows */
639e5c2ddcSdjm       decode_result =
649e5c2ddcSdjm           cbor_stream_decode(source + result->read, source_size - result->read,
659e5c2ddcSdjm                              &callbacks, &context);
66da0d961cSdjm     } else {
679e5c2ddcSdjm       result->error = (struct cbor_error){.code = CBOR_ERR_NOTENOUGHDATA,
689e5c2ddcSdjm                                           .position = result->read};
69da0d961cSdjm       goto error;
70da0d961cSdjm     }
71da0d961cSdjm 
72da0d961cSdjm     switch (decode_result.status) {
73da0d961cSdjm       case CBOR_DECODER_FINISHED:
74da0d961cSdjm         /* Everything OK */
75da0d961cSdjm         {
76da0d961cSdjm           result->read += decode_result.read;
77da0d961cSdjm           break;
78da0d961cSdjm         }
79da0d961cSdjm       case CBOR_DECODER_NEDATA:
80da0d961cSdjm         /* Data length doesn't match MTB expectation */
81da0d961cSdjm         {
82da0d961cSdjm           result->error.code = CBOR_ERR_NOTENOUGHDATA;
83da0d961cSdjm           goto error;
84da0d961cSdjm         }
85da0d961cSdjm       case CBOR_DECODER_ERROR:
86*4dcc46c4Sdjm         /* Reserved/malformed item */
87da0d961cSdjm         {
88da0d961cSdjm           result->error.code = CBOR_ERR_MALFORMATED;
89da0d961cSdjm           goto error;
90da0d961cSdjm         }
91da0d961cSdjm     }
92da0d961cSdjm 
93da0d961cSdjm     if (context.creation_failed) {
94da0d961cSdjm       /* Most likely unsuccessful allocation - our callback has failed */
95da0d961cSdjm       result->error.code = CBOR_ERR_MEMERROR;
96da0d961cSdjm       goto error;
97da0d961cSdjm     } else if (context.syntax_error) {
98da0d961cSdjm       result->error.code = CBOR_ERR_SYNTAXERROR;
99da0d961cSdjm       goto error;
100da0d961cSdjm     }
101da0d961cSdjm   } while (stack.size > 0);
102da0d961cSdjm 
103*4dcc46c4Sdjm   return context.root;
104da0d961cSdjm 
105da0d961cSdjm error:
106da0d961cSdjm   result->error.position = result->read;
1079e5c2ddcSdjm   // debug_print("Failed with decoder error %d at %d\n", result->error.code,
1089e5c2ddcSdjm   // result->error.position); cbor_describe(stack.top->item, stdout);
109da0d961cSdjm   /* Free the stack */
110da0d961cSdjm   while (stack.size > 0) {
111da0d961cSdjm     cbor_decref(&stack.top->item);
112da0d961cSdjm     _cbor_stack_pop(&stack);
113da0d961cSdjm   }
114da0d961cSdjm   return NULL;
115da0d961cSdjm }
116da0d961cSdjm 
_cbor_copy_int(cbor_item_t * item,bool negative)1179e5c2ddcSdjm static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
118da0d961cSdjm   cbor_item_t *res;
119da0d961cSdjm   switch (cbor_int_get_width(item)) {
1209e5c2ddcSdjm     case CBOR_INT_8:
1219e5c2ddcSdjm       res = cbor_build_uint8(cbor_get_uint8(item));
1229e5c2ddcSdjm       break;
1239e5c2ddcSdjm     case CBOR_INT_16:
1249e5c2ddcSdjm       res = cbor_build_uint16(cbor_get_uint16(item));
1259e5c2ddcSdjm       break;
1269e5c2ddcSdjm     case CBOR_INT_32:
1279e5c2ddcSdjm       res = cbor_build_uint32(cbor_get_uint32(item));
1289e5c2ddcSdjm       break;
1299e5c2ddcSdjm     case CBOR_INT_64:
1309e5c2ddcSdjm       res = cbor_build_uint64(cbor_get_uint64(item));
1319e5c2ddcSdjm       break;
132da0d961cSdjm   }
133da0d961cSdjm 
1349e5c2ddcSdjm   if (negative) cbor_mark_negint(res);
135da0d961cSdjm 
136da0d961cSdjm   return res;
137da0d961cSdjm }
138da0d961cSdjm 
_cbor_copy_float_ctrl(cbor_item_t * item)1399e5c2ddcSdjm static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
140*4dcc46c4Sdjm   // cppcheck-suppress missingReturn
141da0d961cSdjm   switch (cbor_float_get_width(item)) {
142da0d961cSdjm     case CBOR_FLOAT_0:
143da0d961cSdjm       return cbor_build_ctrl(cbor_ctrl_value(item));
144da0d961cSdjm     case CBOR_FLOAT_16:
145da0d961cSdjm       return cbor_build_float2(cbor_float_get_float2(item));
146da0d961cSdjm     case CBOR_FLOAT_32:
147da0d961cSdjm       return cbor_build_float4(cbor_float_get_float4(item));
148da0d961cSdjm     case CBOR_FLOAT_64:
149da0d961cSdjm       return cbor_build_float8(cbor_float_get_float8(item));
150da0d961cSdjm   }
151da0d961cSdjm }
152da0d961cSdjm 
cbor_copy(cbor_item_t * item)1539e5c2ddcSdjm cbor_item_t *cbor_copy(cbor_item_t *item) {
154*4dcc46c4Sdjm   // cppcheck-suppress missingReturn
155da0d961cSdjm   switch (cbor_typeof(item)) {
156da0d961cSdjm     case CBOR_TYPE_UINT:
157da0d961cSdjm       return _cbor_copy_int(item, false);
158da0d961cSdjm     case CBOR_TYPE_NEGINT:
159da0d961cSdjm       return _cbor_copy_int(item, true);
160da0d961cSdjm     case CBOR_TYPE_BYTESTRING:
161da0d961cSdjm       if (cbor_bytestring_is_definite(item)) {
1629e5c2ddcSdjm         return cbor_build_bytestring(cbor_bytestring_handle(item),
1639e5c2ddcSdjm                                      cbor_bytestring_length(item));
164da0d961cSdjm       } else {
165da0d961cSdjm         cbor_item_t *res = cbor_new_indefinite_bytestring();
166*4dcc46c4Sdjm         if (res == NULL) {
167*4dcc46c4Sdjm           return NULL;
168*4dcc46c4Sdjm         }
169*4dcc46c4Sdjm 
170*4dcc46c4Sdjm         for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
171*4dcc46c4Sdjm           cbor_item_t *chunk_copy =
172*4dcc46c4Sdjm               cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
173*4dcc46c4Sdjm           if (chunk_copy == NULL) {
174*4dcc46c4Sdjm             cbor_decref(&res);
175*4dcc46c4Sdjm             return NULL;
176*4dcc46c4Sdjm           }
177*4dcc46c4Sdjm           if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
178*4dcc46c4Sdjm             cbor_decref(&chunk_copy);
179*4dcc46c4Sdjm             cbor_decref(&res);
180*4dcc46c4Sdjm             return NULL;
181*4dcc46c4Sdjm           }
182*4dcc46c4Sdjm           cbor_decref(&chunk_copy);
183*4dcc46c4Sdjm         }
184da0d961cSdjm         return res;
185da0d961cSdjm       }
186da0d961cSdjm     case CBOR_TYPE_STRING:
187da0d961cSdjm       if (cbor_string_is_definite(item)) {
1889e5c2ddcSdjm         return cbor_build_stringn((const char *)cbor_string_handle(item),
1899e5c2ddcSdjm                                   cbor_string_length(item));
190da0d961cSdjm       } else {
191da0d961cSdjm         cbor_item_t *res = cbor_new_indefinite_string();
192*4dcc46c4Sdjm         if (res == NULL) {
193*4dcc46c4Sdjm           return NULL;
194*4dcc46c4Sdjm         }
195*4dcc46c4Sdjm 
196*4dcc46c4Sdjm         for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
197*4dcc46c4Sdjm           cbor_item_t *chunk_copy =
198*4dcc46c4Sdjm               cbor_copy(cbor_string_chunks_handle(item)[i]);
199*4dcc46c4Sdjm           if (chunk_copy == NULL) {
200*4dcc46c4Sdjm             cbor_decref(&res);
201*4dcc46c4Sdjm             return NULL;
202*4dcc46c4Sdjm           }
203*4dcc46c4Sdjm           if (!cbor_string_add_chunk(res, chunk_copy)) {
204*4dcc46c4Sdjm             cbor_decref(&chunk_copy);
205*4dcc46c4Sdjm             cbor_decref(&res);
206*4dcc46c4Sdjm             return NULL;
207*4dcc46c4Sdjm           }
208*4dcc46c4Sdjm           cbor_decref(&chunk_copy);
209*4dcc46c4Sdjm         }
210da0d961cSdjm         return res;
211da0d961cSdjm       }
212da0d961cSdjm     case CBOR_TYPE_ARRAY: {
213da0d961cSdjm       cbor_item_t *res;
214*4dcc46c4Sdjm       if (cbor_array_is_definite(item)) {
215da0d961cSdjm         res = cbor_new_definite_array(cbor_array_size(item));
216*4dcc46c4Sdjm       } else {
217da0d961cSdjm         res = cbor_new_indefinite_array();
218*4dcc46c4Sdjm       }
219*4dcc46c4Sdjm       if (res == NULL) {
220*4dcc46c4Sdjm         return NULL;
221*4dcc46c4Sdjm       }
222da0d961cSdjm 
223*4dcc46c4Sdjm       for (size_t i = 0; i < cbor_array_size(item); i++) {
224*4dcc46c4Sdjm         cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
225*4dcc46c4Sdjm         if (entry_copy == NULL) {
226*4dcc46c4Sdjm           cbor_decref(&res);
227*4dcc46c4Sdjm           return NULL;
228*4dcc46c4Sdjm         }
229*4dcc46c4Sdjm         if (!cbor_array_push(res, entry_copy)) {
230*4dcc46c4Sdjm           cbor_decref(&entry_copy);
231*4dcc46c4Sdjm           cbor_decref(&res);
232*4dcc46c4Sdjm           return NULL;
233*4dcc46c4Sdjm         }
234*4dcc46c4Sdjm         cbor_decref(&entry_copy);
235*4dcc46c4Sdjm       }
236da0d961cSdjm       return res;
237da0d961cSdjm     }
238da0d961cSdjm     case CBOR_TYPE_MAP: {
239da0d961cSdjm       cbor_item_t *res;
240*4dcc46c4Sdjm       if (cbor_map_is_definite(item)) {
241da0d961cSdjm         res = cbor_new_definite_map(cbor_map_size(item));
242*4dcc46c4Sdjm       } else {
243da0d961cSdjm         res = cbor_new_indefinite_map();
244*4dcc46c4Sdjm       }
245*4dcc46c4Sdjm       if (res == NULL) {
246*4dcc46c4Sdjm         return NULL;
247*4dcc46c4Sdjm       }
248da0d961cSdjm 
249da0d961cSdjm       struct cbor_pair *it = cbor_map_handle(item);
250*4dcc46c4Sdjm       for (size_t i = 0; i < cbor_map_size(item); i++) {
251*4dcc46c4Sdjm         cbor_item_t *key_copy = cbor_copy(it[i].key);
252*4dcc46c4Sdjm         if (key_copy == NULL) {
253*4dcc46c4Sdjm           cbor_decref(&res);
254*4dcc46c4Sdjm           return NULL;
255*4dcc46c4Sdjm         }
256*4dcc46c4Sdjm         cbor_item_t *value_copy = cbor_copy(it[i].value);
257*4dcc46c4Sdjm         if (value_copy == NULL) {
258*4dcc46c4Sdjm           cbor_decref(&res);
259*4dcc46c4Sdjm           cbor_decref(&key_copy);
260*4dcc46c4Sdjm           return NULL;
261*4dcc46c4Sdjm         }
262*4dcc46c4Sdjm         if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
263*4dcc46c4Sdjm                                                   .value = value_copy})) {
264*4dcc46c4Sdjm           cbor_decref(&res);
265*4dcc46c4Sdjm           cbor_decref(&key_copy);
266*4dcc46c4Sdjm           cbor_decref(&value_copy);
267*4dcc46c4Sdjm           return NULL;
268*4dcc46c4Sdjm         }
269*4dcc46c4Sdjm         cbor_decref(&key_copy);
270*4dcc46c4Sdjm         cbor_decref(&value_copy);
271*4dcc46c4Sdjm       }
272da0d961cSdjm       return res;
273da0d961cSdjm     }
274*4dcc46c4Sdjm     case CBOR_TYPE_TAG: {
275*4dcc46c4Sdjm       cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
276*4dcc46c4Sdjm       if (item_copy == NULL) {
277*4dcc46c4Sdjm         return NULL;
278*4dcc46c4Sdjm       }
279*4dcc46c4Sdjm       cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy);
280*4dcc46c4Sdjm       cbor_decref(&item_copy);
281*4dcc46c4Sdjm       return tag;
282*4dcc46c4Sdjm     }
283da0d961cSdjm     case CBOR_TYPE_FLOAT_CTRL:
284da0d961cSdjm       return _cbor_copy_float_ctrl(item);
285da0d961cSdjm   }
286da0d961cSdjm }
287da0d961cSdjm 
288da0d961cSdjm #if CBOR_PRETTY_PRINTER
289da0d961cSdjm 
290da0d961cSdjm #include <inttypes.h>
291da0d961cSdjm #include <locale.h>
292da0d961cSdjm #include <stdlib.h>
2939e5c2ddcSdjm #include <wchar.h>
294da0d961cSdjm 
295da0d961cSdjm #define __STDC_FORMAT_MACROS
296da0d961cSdjm 
_pow(int b,int ex)2979e5c2ddcSdjm static int _pow(int b, int ex) {
298da0d961cSdjm   if (ex == 0) return 1;
299da0d961cSdjm   int res = b;
300da0d961cSdjm   while (--ex > 0) res *= b;
301da0d961cSdjm   return res;
302da0d961cSdjm }
303da0d961cSdjm 
_cbor_nested_describe(cbor_item_t * item,FILE * out,int indent)3049e5c2ddcSdjm static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
305da0d961cSdjm   setlocale(LC_ALL, "");
306da0d961cSdjm   switch (cbor_typeof(item)) {
307da0d961cSdjm     case CBOR_TYPE_UINT: {
308da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " ");
309da0d961cSdjm       fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
310da0d961cSdjm       fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
311da0d961cSdjm       break;
312*4dcc46c4Sdjm     }
313da0d961cSdjm     case CBOR_TYPE_NEGINT: {
314da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " ");
315da0d961cSdjm       fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
316da0d961cSdjm       fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item));
317da0d961cSdjm       break;
318*4dcc46c4Sdjm     }
319da0d961cSdjm     case CBOR_TYPE_BYTESTRING: {
320da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " ");
321da0d961cSdjm       if (cbor_bytestring_is_indefinite(item)) {
3229e5c2ddcSdjm         fprintf(out, "Indefinite, with %zu chunks:\n",
323da0d961cSdjm                 cbor_bytestring_chunk_count(item));
324da0d961cSdjm         for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
3259e5c2ddcSdjm           _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
326da0d961cSdjm                                 indent + 4);
327da0d961cSdjm       } else {
3289e5c2ddcSdjm         fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item));
329da0d961cSdjm       }
330da0d961cSdjm       break;
331*4dcc46c4Sdjm     }
332da0d961cSdjm     case CBOR_TYPE_STRING: {
333da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " ");
334da0d961cSdjm       if (cbor_string_is_indefinite(item)) {
3359e5c2ddcSdjm         fprintf(out, "Indefinite, with %zu chunks:\n",
336da0d961cSdjm                 cbor_string_chunk_count(item));
337da0d961cSdjm         for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
3389e5c2ddcSdjm           _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
339da0d961cSdjm                                 indent + 4);
340da0d961cSdjm       } else {
3419e5c2ddcSdjm         fprintf(out, "Definite, length %zuB, %zu codepoints\n",
3429e5c2ddcSdjm                 cbor_string_length(item), cbor_string_codepoint_count(item));
343da0d961cSdjm         /* Careful - this doesn't support multibyte characters! */
344da0d961cSdjm         /* Printing those is out of the scope of this demo :) */
345da0d961cSdjm         /* libICU is your friend */
346da0d961cSdjm         fprintf(out, "%*s", indent + 4, " ");
347da0d961cSdjm         /* XXX: no null at the end -> confused vprintf */
348da0d961cSdjm         fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out);
349da0d961cSdjm         fprintf(out, "\n");
350da0d961cSdjm       }
351da0d961cSdjm       break;
352*4dcc46c4Sdjm     }
353da0d961cSdjm     case CBOR_TYPE_ARRAY: {
354da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " ");
355da0d961cSdjm       if (cbor_array_is_definite(item)) {
3569e5c2ddcSdjm         fprintf(out, "Definite, size: %zu\n", cbor_array_size(item));
357da0d961cSdjm       } else {
3589e5c2ddcSdjm         fprintf(out, "Indefinite, size:  %zu\n", cbor_array_size(item));
359da0d961cSdjm       }
360da0d961cSdjm 
361da0d961cSdjm       for (size_t i = 0; i < cbor_array_size(item); i++)
3629e5c2ddcSdjm         _cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4);
363da0d961cSdjm       break;
364*4dcc46c4Sdjm     }
365da0d961cSdjm     case CBOR_TYPE_MAP: {
366da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " ");
367da0d961cSdjm       if (cbor_map_is_definite(item)) {
3689e5c2ddcSdjm         fprintf(out, "Definite, size: %zu\n", cbor_map_size(item));
369da0d961cSdjm       } else {
3709e5c2ddcSdjm         fprintf(out, "Indefinite, size:  %zu\n", cbor_map_size(item));
371da0d961cSdjm       }
372da0d961cSdjm 
373da0d961cSdjm       for (size_t i = 0; i < cbor_map_size(item); i++) {
3749e5c2ddcSdjm         _cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4);
3759e5c2ddcSdjm         _cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4);
376da0d961cSdjm       }
377da0d961cSdjm       break;
378*4dcc46c4Sdjm     }
379da0d961cSdjm     case CBOR_TYPE_TAG: {
380da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " ");
381da0d961cSdjm       fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
382*4dcc46c4Sdjm       _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4);
383da0d961cSdjm       break;
384*4dcc46c4Sdjm     }
385da0d961cSdjm     case CBOR_TYPE_FLOAT_CTRL: {
386da0d961cSdjm       fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " ");
387da0d961cSdjm       if (cbor_float_ctrl_is_ctrl(item)) {
388da0d961cSdjm         if (cbor_is_bool(item))
389d3425be1Sdjm           fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
390da0d961cSdjm         else if (cbor_is_undef(item))
391da0d961cSdjm           fprintf(out, "Undefined\n");
392da0d961cSdjm         else if (cbor_is_null(item))
393da0d961cSdjm           fprintf(out, "Null\n");
394da0d961cSdjm         else
395da0d961cSdjm           fprintf(out, "Simple value %d\n", cbor_ctrl_value(item));
396da0d961cSdjm       } else {
397da0d961cSdjm         fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
398da0d961cSdjm         fprintf(out, "value: %lf\n", cbor_float_get_float(item));
399da0d961cSdjm       }
400da0d961cSdjm       break;
401*4dcc46c4Sdjm     }
402da0d961cSdjm   }
403da0d961cSdjm }
404da0d961cSdjm 
cbor_describe(cbor_item_t * item,FILE * out)4059e5c2ddcSdjm void cbor_describe(cbor_item_t *item, FILE *out) {
406da0d961cSdjm   _cbor_nested_describe(item, out, 0);
407da0d961cSdjm }
408da0d961cSdjm 
409da0d961cSdjm #endif
410