xref: /freebsd/contrib/libcbor/src/cbor/serialization.c (revision 5d3e7166f6a0187fa3f8831b16a06bd9955c21ff)
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 "serialization.h"
910ff414cSEd Maste #include <string.h>
1010ff414cSEd Maste #include "cbor/arrays.h"
1110ff414cSEd Maste #include "cbor/bytestrings.h"
1210ff414cSEd Maste #include "cbor/floats_ctrls.h"
1310ff414cSEd Maste #include "cbor/ints.h"
1410ff414cSEd Maste #include "cbor/maps.h"
1510ff414cSEd Maste #include "cbor/strings.h"
1610ff414cSEd Maste #include "cbor/tags.h"
1710ff414cSEd Maste #include "encoding.h"
1810ff414cSEd Maste #include "internal/memory_utils.h"
1910ff414cSEd Maste 
cbor_serialize(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)2010ff414cSEd Maste size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
2110ff414cSEd Maste                       size_t buffer_size) {
22*5d3e7166SEd Maste   // cppcheck-suppress missingReturn
2310ff414cSEd Maste   switch (cbor_typeof(item)) {
2410ff414cSEd Maste     case CBOR_TYPE_UINT:
2510ff414cSEd Maste       return cbor_serialize_uint(item, buffer, buffer_size);
2610ff414cSEd Maste     case CBOR_TYPE_NEGINT:
2710ff414cSEd Maste       return cbor_serialize_negint(item, buffer, buffer_size);
2810ff414cSEd Maste     case CBOR_TYPE_BYTESTRING:
2910ff414cSEd Maste       return cbor_serialize_bytestring(item, buffer, buffer_size);
3010ff414cSEd Maste     case CBOR_TYPE_STRING:
3110ff414cSEd Maste       return cbor_serialize_string(item, buffer, buffer_size);
3210ff414cSEd Maste     case CBOR_TYPE_ARRAY:
3310ff414cSEd Maste       return cbor_serialize_array(item, buffer, buffer_size);
3410ff414cSEd Maste     case CBOR_TYPE_MAP:
3510ff414cSEd Maste       return cbor_serialize_map(item, buffer, buffer_size);
3610ff414cSEd Maste     case CBOR_TYPE_TAG:
3710ff414cSEd Maste       return cbor_serialize_tag(item, buffer, buffer_size);
3810ff414cSEd Maste     case CBOR_TYPE_FLOAT_CTRL:
3910ff414cSEd Maste       return cbor_serialize_float_ctrl(item, buffer, buffer_size);
40*5d3e7166SEd Maste   }
41*5d3e7166SEd Maste }
42*5d3e7166SEd Maste 
43*5d3e7166SEd Maste /** Largest integer that can be encoded as embedded in the item leading byte. */
44*5d3e7166SEd Maste const uint64_t kMaxEmbeddedInt = 23;
45*5d3e7166SEd Maste 
46*5d3e7166SEd Maste /** How many bytes will a tag for a nested item of a given `size` take when
47*5d3e7166SEd Maste  * encoded.*/
_cbor_encoded_header_size(uint64_t size)48*5d3e7166SEd Maste size_t _cbor_encoded_header_size(uint64_t size) {
49*5d3e7166SEd Maste   if (size <= kMaxEmbeddedInt)
50*5d3e7166SEd Maste     return 1;
51*5d3e7166SEd Maste   else if (size <= UINT8_MAX)
52*5d3e7166SEd Maste     return 2;
53*5d3e7166SEd Maste   else if (size <= UINT16_MAX)
54*5d3e7166SEd Maste     return 3;
55*5d3e7166SEd Maste   else if (size <= UINT32_MAX)
56*5d3e7166SEd Maste     return 5;
57*5d3e7166SEd Maste   else
58*5d3e7166SEd Maste     return 9;
59*5d3e7166SEd Maste }
60*5d3e7166SEd Maste 
cbor_serialized_size(const cbor_item_t * item)61*5d3e7166SEd Maste size_t cbor_serialized_size(const cbor_item_t *item) {
62*5d3e7166SEd Maste   // cppcheck-suppress missingReturn
63*5d3e7166SEd Maste   switch (cbor_typeof(item)) {
64*5d3e7166SEd Maste     case CBOR_TYPE_UINT:
65*5d3e7166SEd Maste     case CBOR_TYPE_NEGINT:
66*5d3e7166SEd Maste       switch (cbor_int_get_width(item)) {
67*5d3e7166SEd Maste         case CBOR_INT_8:
68*5d3e7166SEd Maste           if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;
69*5d3e7166SEd Maste           return 2;
70*5d3e7166SEd Maste         case CBOR_INT_16:
71*5d3e7166SEd Maste           return 3;
72*5d3e7166SEd Maste         case CBOR_INT_32:
73*5d3e7166SEd Maste           return 5;
74*5d3e7166SEd Maste         case CBOR_INT_64:
75*5d3e7166SEd Maste           return 9;
76*5d3e7166SEd Maste       }
77*5d3e7166SEd Maste     // Note: We do not _cbor_safe_signaling_add zero-length definite strings,
78*5d3e7166SEd Maste     // they would cause zeroes to propagate. All other items are at least one
79*5d3e7166SEd Maste     // byte.
80*5d3e7166SEd Maste     case CBOR_TYPE_BYTESTRING: {
81*5d3e7166SEd Maste       if (cbor_bytestring_is_definite(item)) {
82*5d3e7166SEd Maste         size_t header_size =
83*5d3e7166SEd Maste             _cbor_encoded_header_size(cbor_bytestring_length(item));
84*5d3e7166SEd Maste         if (cbor_bytestring_length(item) == 0) return header_size;
85*5d3e7166SEd Maste         return _cbor_safe_signaling_add(header_size,
86*5d3e7166SEd Maste                                         cbor_bytestring_length(item));
87*5d3e7166SEd Maste       }
88*5d3e7166SEd Maste       size_t indef_bytestring_size = 2;  // Leading byte + break
89*5d3e7166SEd Maste       cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
90*5d3e7166SEd Maste       for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
91*5d3e7166SEd Maste         indef_bytestring_size = _cbor_safe_signaling_add(
92*5d3e7166SEd Maste             indef_bytestring_size, cbor_serialized_size(chunks[i]));
93*5d3e7166SEd Maste       }
94*5d3e7166SEd Maste       return indef_bytestring_size;
95*5d3e7166SEd Maste     }
96*5d3e7166SEd Maste     case CBOR_TYPE_STRING: {
97*5d3e7166SEd Maste       if (cbor_string_is_definite(item)) {
98*5d3e7166SEd Maste         size_t header_size =
99*5d3e7166SEd Maste             _cbor_encoded_header_size(cbor_string_length(item));
100*5d3e7166SEd Maste         if (cbor_string_length(item) == 0) return header_size;
101*5d3e7166SEd Maste         return _cbor_safe_signaling_add(header_size, cbor_string_length(item));
102*5d3e7166SEd Maste       }
103*5d3e7166SEd Maste       size_t indef_string_size = 2;  // Leading byte + break
104*5d3e7166SEd Maste       cbor_item_t **chunks = cbor_string_chunks_handle(item);
105*5d3e7166SEd Maste       for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
106*5d3e7166SEd Maste         indef_string_size = _cbor_safe_signaling_add(
107*5d3e7166SEd Maste             indef_string_size, cbor_serialized_size(chunks[i]));
108*5d3e7166SEd Maste       }
109*5d3e7166SEd Maste       return indef_string_size;
110*5d3e7166SEd Maste     }
111*5d3e7166SEd Maste     case CBOR_TYPE_ARRAY: {
112*5d3e7166SEd Maste       size_t array_size = cbor_array_is_definite(item)
113*5d3e7166SEd Maste                               ? _cbor_encoded_header_size(cbor_array_size(item))
114*5d3e7166SEd Maste                               : 2;  // Leading byte + break
115*5d3e7166SEd Maste       cbor_item_t **items = cbor_array_handle(item);
116*5d3e7166SEd Maste       for (size_t i = 0; i < cbor_array_size(item); i++) {
117*5d3e7166SEd Maste         array_size = _cbor_safe_signaling_add(array_size,
118*5d3e7166SEd Maste                                               cbor_serialized_size(items[i]));
119*5d3e7166SEd Maste       }
120*5d3e7166SEd Maste       return array_size;
121*5d3e7166SEd Maste     }
122*5d3e7166SEd Maste     case CBOR_TYPE_MAP: {
123*5d3e7166SEd Maste       size_t map_size = cbor_map_is_definite(item)
124*5d3e7166SEd Maste                             ? _cbor_encoded_header_size(cbor_map_size(item))
125*5d3e7166SEd Maste                             : 2;  // Leading byte + break
126*5d3e7166SEd Maste       struct cbor_pair *items = cbor_map_handle(item);
127*5d3e7166SEd Maste       for (size_t i = 0; i < cbor_map_size(item); i++) {
128*5d3e7166SEd Maste         map_size = _cbor_safe_signaling_add(
129*5d3e7166SEd Maste             map_size,
130*5d3e7166SEd Maste             _cbor_safe_signaling_add(cbor_serialized_size(items[i].key),
131*5d3e7166SEd Maste                                      cbor_serialized_size(items[i].value)));
132*5d3e7166SEd Maste       }
133*5d3e7166SEd Maste       return map_size;
134*5d3e7166SEd Maste     }
135*5d3e7166SEd Maste     case CBOR_TYPE_TAG: {
136*5d3e7166SEd Maste       return _cbor_safe_signaling_add(
137*5d3e7166SEd Maste           _cbor_encoded_header_size(cbor_tag_value(item)),
138*5d3e7166SEd Maste           cbor_serialized_size(cbor_move(cbor_tag_item(item))));
139*5d3e7166SEd Maste     }
140*5d3e7166SEd Maste     case CBOR_TYPE_FLOAT_CTRL:
141*5d3e7166SEd Maste       switch (cbor_float_get_width(item)) {
142*5d3e7166SEd Maste         case CBOR_FLOAT_0:
143*5d3e7166SEd Maste           return _cbor_encoded_header_size(cbor_ctrl_value(item));
144*5d3e7166SEd Maste         case CBOR_FLOAT_16:
145*5d3e7166SEd Maste           return 3;
146*5d3e7166SEd Maste         case CBOR_FLOAT_32:
147*5d3e7166SEd Maste           return 5;
148*5d3e7166SEd Maste         case CBOR_FLOAT_64:
149*5d3e7166SEd Maste           return 9;
150*5d3e7166SEd Maste       }
15110ff414cSEd Maste   }
15210ff414cSEd Maste }
15310ff414cSEd Maste 
cbor_serialize_alloc(const cbor_item_t * item,unsigned char ** buffer,size_t * buffer_size)15410ff414cSEd Maste size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
15510ff414cSEd Maste                             size_t *buffer_size) {
156*5d3e7166SEd Maste   *buffer = NULL;
157*5d3e7166SEd Maste   size_t serialized_size = cbor_serialized_size(item);
158*5d3e7166SEd Maste   if (serialized_size == 0) {
159*5d3e7166SEd Maste     if (buffer_size != NULL) *buffer_size = 0;
160*5d3e7166SEd Maste     return 0;
161*5d3e7166SEd Maste   }
162*5d3e7166SEd Maste   *buffer = _cbor_malloc(serialized_size);
163*5d3e7166SEd Maste   if (*buffer == NULL) {
164*5d3e7166SEd Maste     if (buffer_size != NULL) *buffer_size = 0;
16510ff414cSEd Maste     return 0;
16610ff414cSEd Maste   }
16710ff414cSEd Maste 
168*5d3e7166SEd Maste   size_t written = cbor_serialize(item, *buffer, serialized_size);
169*5d3e7166SEd Maste   CBOR_ASSERT(written == serialized_size);
170*5d3e7166SEd Maste   if (buffer_size != NULL) *buffer_size = serialized_size;
17110ff414cSEd Maste   return written;
17210ff414cSEd Maste }
17310ff414cSEd Maste 
cbor_serialize_uint(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)17410ff414cSEd Maste size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
17510ff414cSEd Maste                            size_t buffer_size) {
176*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_uint(item));
177*5d3e7166SEd Maste   // cppcheck-suppress missingReturn
17810ff414cSEd Maste   switch (cbor_int_get_width(item)) {
17910ff414cSEd Maste     case CBOR_INT_8:
18010ff414cSEd Maste       return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
18110ff414cSEd Maste     case CBOR_INT_16:
18210ff414cSEd Maste       return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);
18310ff414cSEd Maste     case CBOR_INT_32:
18410ff414cSEd Maste       return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
18510ff414cSEd Maste     case CBOR_INT_64:
18610ff414cSEd Maste       return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
18710ff414cSEd Maste   }
18810ff414cSEd Maste }
18910ff414cSEd Maste 
cbor_serialize_negint(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)19010ff414cSEd Maste size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
19110ff414cSEd Maste                              size_t buffer_size) {
192*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_negint(item));
193*5d3e7166SEd Maste   // cppcheck-suppress missingReturn
19410ff414cSEd Maste   switch (cbor_int_get_width(item)) {
19510ff414cSEd Maste     case CBOR_INT_8:
19610ff414cSEd Maste       return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
19710ff414cSEd Maste     case CBOR_INT_16:
19810ff414cSEd Maste       return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);
19910ff414cSEd Maste     case CBOR_INT_32:
20010ff414cSEd Maste       return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
20110ff414cSEd Maste     case CBOR_INT_64:
20210ff414cSEd Maste       return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
20310ff414cSEd Maste   }
20410ff414cSEd Maste }
20510ff414cSEd Maste 
cbor_serialize_bytestring(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)20610ff414cSEd Maste size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer,
20710ff414cSEd Maste                                  size_t buffer_size) {
208*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_bytestring(item));
20910ff414cSEd Maste   if (cbor_bytestring_is_definite(item)) {
21010ff414cSEd Maste     size_t length = cbor_bytestring_length(item);
21110ff414cSEd Maste     size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
212*5d3e7166SEd Maste     if (written > 0 && (buffer_size - written >= length)) {
21310ff414cSEd Maste       memcpy(buffer + written, cbor_bytestring_handle(item), length);
21410ff414cSEd Maste       return written + length;
215*5d3e7166SEd Maste     }
21610ff414cSEd Maste     return 0;
21710ff414cSEd Maste   } else {
218*5d3e7166SEd Maste     CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
21910ff414cSEd Maste     size_t chunk_count = cbor_bytestring_chunk_count(item);
22010ff414cSEd Maste     size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
22110ff414cSEd Maste     if (written == 0) return 0;
22210ff414cSEd Maste 
22310ff414cSEd Maste     cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
22410ff414cSEd Maste     for (size_t i = 0; i < chunk_count; i++) {
22510ff414cSEd Maste       size_t chunk_written = cbor_serialize_bytestring(
22610ff414cSEd Maste           chunks[i], buffer + written, buffer_size - written);
227*5d3e7166SEd Maste       if (chunk_written == 0) return 0;
22810ff414cSEd Maste       written += chunk_written;
22910ff414cSEd Maste     }
230*5d3e7166SEd Maste 
231*5d3e7166SEd Maste     size_t break_written =
232*5d3e7166SEd Maste         cbor_encode_break(buffer + written, buffer_size - written);
233*5d3e7166SEd Maste     if (break_written == 0) return 0;
234*5d3e7166SEd Maste     return written + break_written;
23510ff414cSEd Maste   }
23610ff414cSEd Maste }
23710ff414cSEd Maste 
cbor_serialize_string(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)23810ff414cSEd Maste size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,
23910ff414cSEd Maste                              size_t buffer_size) {
240*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_string(item));
24110ff414cSEd Maste   if (cbor_string_is_definite(item)) {
24210ff414cSEd Maste     size_t length = cbor_string_length(item);
24310ff414cSEd Maste     size_t written = cbor_encode_string_start(length, buffer, buffer_size);
24410ff414cSEd Maste     if (written && (buffer_size - written >= length)) {
24510ff414cSEd Maste       memcpy(buffer + written, cbor_string_handle(item), length);
24610ff414cSEd Maste       return written + length;
247*5d3e7166SEd Maste     }
24810ff414cSEd Maste     return 0;
24910ff414cSEd Maste   } else {
250*5d3e7166SEd Maste     CBOR_ASSERT(cbor_string_is_indefinite(item));
25110ff414cSEd Maste     size_t chunk_count = cbor_string_chunk_count(item);
25210ff414cSEd Maste     size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
25310ff414cSEd Maste     if (written == 0) return 0;
25410ff414cSEd Maste 
25510ff414cSEd Maste     cbor_item_t **chunks = cbor_string_chunks_handle(item);
25610ff414cSEd Maste     for (size_t i = 0; i < chunk_count; i++) {
25710ff414cSEd Maste       size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,
25810ff414cSEd Maste                                                    buffer_size - written);
259*5d3e7166SEd Maste       if (chunk_written == 0) return 0;
26010ff414cSEd Maste       written += chunk_written;
26110ff414cSEd Maste     }
262*5d3e7166SEd Maste 
263*5d3e7166SEd Maste     size_t break_written =
264*5d3e7166SEd Maste         cbor_encode_break(buffer + written, buffer_size - written);
265*5d3e7166SEd Maste     if (break_written == 0) return 0;
266*5d3e7166SEd Maste     return written + break_written;
26710ff414cSEd Maste   }
26810ff414cSEd Maste }
26910ff414cSEd Maste 
cbor_serialize_array(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)27010ff414cSEd Maste size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,
27110ff414cSEd Maste                             size_t buffer_size) {
272*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_array(item));
27310ff414cSEd Maste   size_t size = cbor_array_size(item), written = 0;
27410ff414cSEd Maste   cbor_item_t **handle = cbor_array_handle(item);
27510ff414cSEd Maste   if (cbor_array_is_definite(item)) {
27610ff414cSEd Maste     written = cbor_encode_array_start(size, buffer, buffer_size);
27710ff414cSEd Maste   } else {
278*5d3e7166SEd Maste     CBOR_ASSERT(cbor_array_is_indefinite(item));
27910ff414cSEd Maste     written = cbor_encode_indef_array_start(buffer, buffer_size);
28010ff414cSEd Maste   }
28110ff414cSEd Maste   if (written == 0) return 0;
28210ff414cSEd Maste 
28310ff414cSEd Maste   for (size_t i = 0; i < size; i++) {
284*5d3e7166SEd Maste     size_t item_written =
28510ff414cSEd Maste         cbor_serialize(*(handle++), buffer + written, buffer_size - written);
286*5d3e7166SEd Maste     if (item_written == 0) return 0;
28710ff414cSEd Maste     written += item_written;
28810ff414cSEd Maste   }
28910ff414cSEd Maste 
29010ff414cSEd Maste   if (cbor_array_is_definite(item)) {
29110ff414cSEd Maste     return written;
29210ff414cSEd Maste   } else {
293*5d3e7166SEd Maste     CBOR_ASSERT(cbor_array_is_indefinite(item));
294*5d3e7166SEd Maste     size_t break_written =
295*5d3e7166SEd Maste         cbor_encode_break(buffer + written, buffer_size - written);
296*5d3e7166SEd Maste     if (break_written == 0) return 0;
297*5d3e7166SEd Maste     return written + break_written;
29810ff414cSEd Maste   }
29910ff414cSEd Maste }
30010ff414cSEd Maste 
cbor_serialize_map(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)30110ff414cSEd Maste size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,
30210ff414cSEd Maste                           size_t buffer_size) {
303*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_map(item));
30410ff414cSEd Maste   size_t size = cbor_map_size(item), written = 0;
30510ff414cSEd Maste   struct cbor_pair *handle = cbor_map_handle(item);
30610ff414cSEd Maste 
30710ff414cSEd Maste   if (cbor_map_is_definite(item)) {
30810ff414cSEd Maste     written = cbor_encode_map_start(size, buffer, buffer_size);
30910ff414cSEd Maste   } else {
310*5d3e7166SEd Maste     CBOR_ASSERT(cbor_map_is_indefinite(item));
31110ff414cSEd Maste     written = cbor_encode_indef_map_start(buffer, buffer_size);
31210ff414cSEd Maste   }
31310ff414cSEd Maste   if (written == 0) return 0;
31410ff414cSEd Maste 
31510ff414cSEd Maste   for (size_t i = 0; i < size; i++) {
316*5d3e7166SEd Maste     size_t item_written =
31710ff414cSEd Maste         cbor_serialize(handle->key, buffer + written, buffer_size - written);
318*5d3e7166SEd Maste     if (item_written == 0) {
31910ff414cSEd Maste       return 0;
320*5d3e7166SEd Maste     }
32110ff414cSEd Maste     written += item_written;
32210ff414cSEd Maste     item_written = cbor_serialize((handle++)->value, buffer + written,
32310ff414cSEd Maste                                   buffer_size - written);
324*5d3e7166SEd Maste     if (item_written == 0) return 0;
32510ff414cSEd Maste     written += item_written;
32610ff414cSEd Maste   }
32710ff414cSEd Maste 
32810ff414cSEd Maste   if (cbor_map_is_definite(item)) {
32910ff414cSEd Maste     return written;
33010ff414cSEd Maste   } else {
331*5d3e7166SEd Maste     CBOR_ASSERT(cbor_map_is_indefinite(item));
332*5d3e7166SEd Maste     size_t break_written =
333*5d3e7166SEd Maste         cbor_encode_break(buffer + written, buffer_size - written);
334*5d3e7166SEd Maste     if (break_written == 0) return 0;
335*5d3e7166SEd Maste     return written + break_written;
33610ff414cSEd Maste   }
33710ff414cSEd Maste }
33810ff414cSEd Maste 
cbor_serialize_tag(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)33910ff414cSEd Maste size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,
34010ff414cSEd Maste                           size_t buffer_size) {
341*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_tag(item));
34210ff414cSEd Maste   size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
34310ff414cSEd Maste   if (written == 0) return 0;
34410ff414cSEd Maste 
34510ff414cSEd Maste   size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),
34610ff414cSEd Maste                                        buffer + written, buffer_size - written);
347*5d3e7166SEd Maste   if (item_written == 0) return 0;
34810ff414cSEd Maste   return written + item_written;
34910ff414cSEd Maste }
35010ff414cSEd Maste 
cbor_serialize_float_ctrl(const cbor_item_t * item,unsigned char * buffer,size_t buffer_size)35110ff414cSEd Maste size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
35210ff414cSEd Maste                                  size_t buffer_size) {
353*5d3e7166SEd Maste   CBOR_ASSERT(cbor_isa_float_ctrl(item));
354*5d3e7166SEd Maste   // cppcheck-suppress missingReturn
35510ff414cSEd Maste   switch (cbor_float_get_width(item)) {
35610ff414cSEd Maste     case CBOR_FLOAT_0:
35710ff414cSEd Maste       /* CTRL - special treatment */
35810ff414cSEd Maste       return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);
35910ff414cSEd Maste     case CBOR_FLOAT_16:
36010ff414cSEd Maste       return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);
36110ff414cSEd Maste     case CBOR_FLOAT_32:
36210ff414cSEd Maste       return cbor_encode_single(cbor_float_get_float4(item), buffer,
36310ff414cSEd Maste                                 buffer_size);
36410ff414cSEd Maste     case CBOR_FLOAT_64:
36510ff414cSEd Maste       return cbor_encode_double(cbor_float_get_float8(item), buffer,
36610ff414cSEd Maste                                 buffer_size);
36710ff414cSEd Maste   }
36810ff414cSEd Maste }
369