xref: /freebsd/contrib/libcbor/src/cbor/serialization.c (revision 10ff414c14eef433d8157f0c17904d740693933b)
1*10ff414cSEd Maste /*
2*10ff414cSEd Maste  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3*10ff414cSEd Maste  *
4*10ff414cSEd Maste  * libcbor is free software; you can redistribute it and/or modify
5*10ff414cSEd Maste  * it under the terms of the MIT license. See LICENSE for details.
6*10ff414cSEd Maste  */
7*10ff414cSEd Maste 
8*10ff414cSEd Maste #include "serialization.h"
9*10ff414cSEd Maste #include <string.h>
10*10ff414cSEd Maste #include "cbor/arrays.h"
11*10ff414cSEd Maste #include "cbor/bytestrings.h"
12*10ff414cSEd Maste #include "cbor/floats_ctrls.h"
13*10ff414cSEd Maste #include "cbor/ints.h"
14*10ff414cSEd Maste #include "cbor/maps.h"
15*10ff414cSEd Maste #include "cbor/strings.h"
16*10ff414cSEd Maste #include "cbor/tags.h"
17*10ff414cSEd Maste #include "encoding.h"
18*10ff414cSEd Maste #include "internal/memory_utils.h"
19*10ff414cSEd Maste 
20*10ff414cSEd Maste size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
21*10ff414cSEd Maste                       size_t buffer_size) {
22*10ff414cSEd Maste   switch (cbor_typeof(item)) {
23*10ff414cSEd Maste     case CBOR_TYPE_UINT:
24*10ff414cSEd Maste       return cbor_serialize_uint(item, buffer, buffer_size);
25*10ff414cSEd Maste     case CBOR_TYPE_NEGINT:
26*10ff414cSEd Maste       return cbor_serialize_negint(item, buffer, buffer_size);
27*10ff414cSEd Maste     case CBOR_TYPE_BYTESTRING:
28*10ff414cSEd Maste       return cbor_serialize_bytestring(item, buffer, buffer_size);
29*10ff414cSEd Maste     case CBOR_TYPE_STRING:
30*10ff414cSEd Maste       return cbor_serialize_string(item, buffer, buffer_size);
31*10ff414cSEd Maste     case CBOR_TYPE_ARRAY:
32*10ff414cSEd Maste       return cbor_serialize_array(item, buffer, buffer_size);
33*10ff414cSEd Maste     case CBOR_TYPE_MAP:
34*10ff414cSEd Maste       return cbor_serialize_map(item, buffer, buffer_size);
35*10ff414cSEd Maste     case CBOR_TYPE_TAG:
36*10ff414cSEd Maste       return cbor_serialize_tag(item, buffer, buffer_size);
37*10ff414cSEd Maste     case CBOR_TYPE_FLOAT_CTRL:
38*10ff414cSEd Maste       return cbor_serialize_float_ctrl(item, buffer, buffer_size);
39*10ff414cSEd Maste     default:
40*10ff414cSEd Maste       return 0;
41*10ff414cSEd Maste   }
42*10ff414cSEd Maste }
43*10ff414cSEd Maste 
44*10ff414cSEd Maste size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
45*10ff414cSEd Maste                             size_t *buffer_size) {
46*10ff414cSEd Maste   size_t bfr_size = 32;
47*10ff414cSEd Maste   unsigned char *bfr = _CBOR_MALLOC(bfr_size), *tmp_bfr;
48*10ff414cSEd Maste   if (bfr == NULL) {
49*10ff414cSEd Maste     return 0;
50*10ff414cSEd Maste   }
51*10ff414cSEd Maste 
52*10ff414cSEd Maste   size_t written;
53*10ff414cSEd Maste 
54*10ff414cSEd Maste   /* This is waaay too optimistic - figure out something smarter (eventually) */
55*10ff414cSEd Maste   while ((written = cbor_serialize(item, bfr, bfr_size)) == 0) {
56*10ff414cSEd Maste     if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, bfr_size)) {
57*10ff414cSEd Maste       _CBOR_FREE(bfr);
58*10ff414cSEd Maste       return 0;
59*10ff414cSEd Maste     }
60*10ff414cSEd Maste 
61*10ff414cSEd Maste     tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2);
62*10ff414cSEd Maste 
63*10ff414cSEd Maste     if (tmp_bfr == NULL) {
64*10ff414cSEd Maste       _CBOR_FREE(bfr);
65*10ff414cSEd Maste       return 0;
66*10ff414cSEd Maste     }
67*10ff414cSEd Maste     bfr = tmp_bfr;
68*10ff414cSEd Maste   }
69*10ff414cSEd Maste   *buffer = bfr;
70*10ff414cSEd Maste   *buffer_size = bfr_size;
71*10ff414cSEd Maste   return written;
72*10ff414cSEd Maste }
73*10ff414cSEd Maste 
74*10ff414cSEd Maste size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
75*10ff414cSEd Maste                            size_t buffer_size) {
76*10ff414cSEd Maste   assert(cbor_isa_uint(item));
77*10ff414cSEd Maste   switch (cbor_int_get_width(item)) {
78*10ff414cSEd Maste     case CBOR_INT_8:
79*10ff414cSEd Maste       return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
80*10ff414cSEd Maste     case CBOR_INT_16:
81*10ff414cSEd Maste       return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);
82*10ff414cSEd Maste     case CBOR_INT_32:
83*10ff414cSEd Maste       return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
84*10ff414cSEd Maste     case CBOR_INT_64:
85*10ff414cSEd Maste       return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
86*10ff414cSEd Maste     default:
87*10ff414cSEd Maste       return 0;
88*10ff414cSEd Maste   }
89*10ff414cSEd Maste }
90*10ff414cSEd Maste 
91*10ff414cSEd Maste size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
92*10ff414cSEd Maste                              size_t buffer_size) {
93*10ff414cSEd Maste   assert(cbor_isa_negint(item));
94*10ff414cSEd Maste   switch (cbor_int_get_width(item)) {
95*10ff414cSEd Maste     case CBOR_INT_8:
96*10ff414cSEd Maste       return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
97*10ff414cSEd Maste     case CBOR_INT_16:
98*10ff414cSEd Maste       return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);
99*10ff414cSEd Maste     case CBOR_INT_32:
100*10ff414cSEd Maste       return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
101*10ff414cSEd Maste     case CBOR_INT_64:
102*10ff414cSEd Maste       return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
103*10ff414cSEd Maste     default:
104*10ff414cSEd Maste       return 0;
105*10ff414cSEd Maste   }
106*10ff414cSEd Maste }
107*10ff414cSEd Maste 
108*10ff414cSEd Maste size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer,
109*10ff414cSEd Maste                                  size_t buffer_size) {
110*10ff414cSEd Maste   assert(cbor_isa_bytestring(item));
111*10ff414cSEd Maste   if (cbor_bytestring_is_definite(item)) {
112*10ff414cSEd Maste     size_t length = cbor_bytestring_length(item);
113*10ff414cSEd Maste     size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
114*10ff414cSEd Maste     if (written && (buffer_size - written >= length)) {
115*10ff414cSEd Maste       memcpy(buffer + written, cbor_bytestring_handle(item), length);
116*10ff414cSEd Maste       return written + length;
117*10ff414cSEd Maste     } else
118*10ff414cSEd Maste       return 0;
119*10ff414cSEd Maste   } else {
120*10ff414cSEd Maste     assert(cbor_bytestring_is_indefinite(item));
121*10ff414cSEd Maste     size_t chunk_count = cbor_bytestring_chunk_count(item);
122*10ff414cSEd Maste     size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
123*10ff414cSEd Maste 
124*10ff414cSEd Maste     if (written == 0) return 0;
125*10ff414cSEd Maste 
126*10ff414cSEd Maste     cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
127*10ff414cSEd Maste     for (size_t i = 0; i < chunk_count; i++) {
128*10ff414cSEd Maste       size_t chunk_written = cbor_serialize_bytestring(
129*10ff414cSEd Maste           chunks[i], buffer + written, buffer_size - written);
130*10ff414cSEd Maste       if (chunk_written == 0)
131*10ff414cSEd Maste         return 0;
132*10ff414cSEd Maste       else
133*10ff414cSEd Maste         written += chunk_written;
134*10ff414cSEd Maste     }
135*10ff414cSEd Maste     if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
136*10ff414cSEd Maste       return written + 1;
137*10ff414cSEd Maste     else
138*10ff414cSEd Maste       return 0;
139*10ff414cSEd Maste   }
140*10ff414cSEd Maste }
141*10ff414cSEd Maste 
142*10ff414cSEd Maste size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,
143*10ff414cSEd Maste                              size_t buffer_size) {
144*10ff414cSEd Maste   assert(cbor_isa_string(item));
145*10ff414cSEd Maste   if (cbor_string_is_definite(item)) {
146*10ff414cSEd Maste     size_t length = cbor_string_length(item);
147*10ff414cSEd Maste     size_t written = cbor_encode_string_start(length, buffer, buffer_size);
148*10ff414cSEd Maste     if (written && (buffer_size - written >= length)) {
149*10ff414cSEd Maste       memcpy(buffer + written, cbor_string_handle(item), length);
150*10ff414cSEd Maste       return written + length;
151*10ff414cSEd Maste     } else
152*10ff414cSEd Maste       return 0;
153*10ff414cSEd Maste   } else {
154*10ff414cSEd Maste     assert(cbor_string_is_indefinite(item));
155*10ff414cSEd Maste     size_t chunk_count = cbor_string_chunk_count(item);
156*10ff414cSEd Maste     size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
157*10ff414cSEd Maste 
158*10ff414cSEd Maste     if (written == 0) return 0;
159*10ff414cSEd Maste 
160*10ff414cSEd Maste     cbor_item_t **chunks = cbor_string_chunks_handle(item);
161*10ff414cSEd Maste     for (size_t i = 0; i < chunk_count; i++) {
162*10ff414cSEd Maste       size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,
163*10ff414cSEd Maste                                                    buffer_size - written);
164*10ff414cSEd Maste       if (chunk_written == 0)
165*10ff414cSEd Maste         return 0;
166*10ff414cSEd Maste       else
167*10ff414cSEd Maste         written += chunk_written;
168*10ff414cSEd Maste     }
169*10ff414cSEd Maste     if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
170*10ff414cSEd Maste       return written + 1;
171*10ff414cSEd Maste     else
172*10ff414cSEd Maste       return 0;
173*10ff414cSEd Maste   }
174*10ff414cSEd Maste }
175*10ff414cSEd Maste 
176*10ff414cSEd Maste size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,
177*10ff414cSEd Maste                             size_t buffer_size) {
178*10ff414cSEd Maste   assert(cbor_isa_array(item));
179*10ff414cSEd Maste   size_t size = cbor_array_size(item), written = 0;
180*10ff414cSEd Maste   cbor_item_t **handle = cbor_array_handle(item);
181*10ff414cSEd Maste   if (cbor_array_is_definite(item)) {
182*10ff414cSEd Maste     written = cbor_encode_array_start(size, buffer, buffer_size);
183*10ff414cSEd Maste   } else {
184*10ff414cSEd Maste     assert(cbor_array_is_indefinite(item));
185*10ff414cSEd Maste     written = cbor_encode_indef_array_start(buffer, buffer_size);
186*10ff414cSEd Maste   }
187*10ff414cSEd Maste   if (written == 0) return 0;
188*10ff414cSEd Maste 
189*10ff414cSEd Maste   size_t item_written;
190*10ff414cSEd Maste   for (size_t i = 0; i < size; i++) {
191*10ff414cSEd Maste     item_written =
192*10ff414cSEd Maste         cbor_serialize(*(handle++), buffer + written, buffer_size - written);
193*10ff414cSEd Maste     if (item_written == 0)
194*10ff414cSEd Maste       return 0;
195*10ff414cSEd Maste     else
196*10ff414cSEd Maste       written += item_written;
197*10ff414cSEd Maste   }
198*10ff414cSEd Maste 
199*10ff414cSEd Maste   if (cbor_array_is_definite(item)) {
200*10ff414cSEd Maste     return written;
201*10ff414cSEd Maste   } else {
202*10ff414cSEd Maste     assert(cbor_array_is_indefinite(item));
203*10ff414cSEd Maste     item_written = cbor_encode_break(buffer + written, buffer_size - written);
204*10ff414cSEd Maste     if (item_written == 0)
205*10ff414cSEd Maste       return 0;
206*10ff414cSEd Maste     else
207*10ff414cSEd Maste       return written + 1;
208*10ff414cSEd Maste   }
209*10ff414cSEd Maste }
210*10ff414cSEd Maste 
211*10ff414cSEd Maste size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,
212*10ff414cSEd Maste                           size_t buffer_size) {
213*10ff414cSEd Maste   assert(cbor_isa_map(item));
214*10ff414cSEd Maste   size_t size = cbor_map_size(item), written = 0;
215*10ff414cSEd Maste   struct cbor_pair *handle = cbor_map_handle(item);
216*10ff414cSEd Maste 
217*10ff414cSEd Maste   if (cbor_map_is_definite(item)) {
218*10ff414cSEd Maste     written = cbor_encode_map_start(size, buffer, buffer_size);
219*10ff414cSEd Maste   } else {
220*10ff414cSEd Maste     assert(cbor_map_is_indefinite(item));
221*10ff414cSEd Maste     written = cbor_encode_indef_map_start(buffer, buffer_size);
222*10ff414cSEd Maste   }
223*10ff414cSEd Maste   if (written == 0) return 0;
224*10ff414cSEd Maste 
225*10ff414cSEd Maste   size_t item_written;
226*10ff414cSEd Maste   for (size_t i = 0; i < size; i++) {
227*10ff414cSEd Maste     item_written =
228*10ff414cSEd Maste         cbor_serialize(handle->key, buffer + written, buffer_size - written);
229*10ff414cSEd Maste     if (item_written == 0)
230*10ff414cSEd Maste       return 0;
231*10ff414cSEd Maste     else
232*10ff414cSEd Maste       written += item_written;
233*10ff414cSEd Maste     item_written = cbor_serialize((handle++)->value, buffer + written,
234*10ff414cSEd Maste                                   buffer_size - written);
235*10ff414cSEd Maste     if (item_written == 0)
236*10ff414cSEd Maste       return 0;
237*10ff414cSEd Maste     else
238*10ff414cSEd Maste       written += item_written;
239*10ff414cSEd Maste   }
240*10ff414cSEd Maste 
241*10ff414cSEd Maste   if (cbor_map_is_definite(item)) {
242*10ff414cSEd Maste     return written;
243*10ff414cSEd Maste   } else {
244*10ff414cSEd Maste     assert(cbor_map_is_indefinite(item));
245*10ff414cSEd Maste     item_written = cbor_encode_break(buffer + written, buffer_size - written);
246*10ff414cSEd Maste     if (item_written == 0)
247*10ff414cSEd Maste       return 0;
248*10ff414cSEd Maste     else
249*10ff414cSEd Maste       return written + 1;
250*10ff414cSEd Maste   }
251*10ff414cSEd Maste }
252*10ff414cSEd Maste 
253*10ff414cSEd Maste size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,
254*10ff414cSEd Maste                           size_t buffer_size) {
255*10ff414cSEd Maste   assert(cbor_isa_tag(item));
256*10ff414cSEd Maste   size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
257*10ff414cSEd Maste   if (written == 0) return 0;
258*10ff414cSEd Maste 
259*10ff414cSEd Maste   size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),
260*10ff414cSEd Maste                                        buffer + written, buffer_size - written);
261*10ff414cSEd Maste   if (item_written == 0)
262*10ff414cSEd Maste     return 0;
263*10ff414cSEd Maste   else
264*10ff414cSEd Maste     return written + item_written;
265*10ff414cSEd Maste }
266*10ff414cSEd Maste 
267*10ff414cSEd Maste size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
268*10ff414cSEd Maste                                  size_t buffer_size) {
269*10ff414cSEd Maste   assert(cbor_isa_float_ctrl(item));
270*10ff414cSEd Maste   switch (cbor_float_get_width(item)) {
271*10ff414cSEd Maste     case CBOR_FLOAT_0:
272*10ff414cSEd Maste       /* CTRL - special treatment */
273*10ff414cSEd Maste       return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);
274*10ff414cSEd Maste     case CBOR_FLOAT_16:
275*10ff414cSEd Maste       return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);
276*10ff414cSEd Maste     case CBOR_FLOAT_32:
277*10ff414cSEd Maste       return cbor_encode_single(cbor_float_get_float4(item), buffer,
278*10ff414cSEd Maste                                 buffer_size);
279*10ff414cSEd Maste     case CBOR_FLOAT_64:
280*10ff414cSEd Maste       return cbor_encode_double(cbor_float_get_float8(item), buffer,
281*10ff414cSEd Maste                                 buffer_size);
282*10ff414cSEd Maste   }
283*10ff414cSEd Maste 
284*10ff414cSEd Maste   /* Should never happen - make the compiler happy */
285*10ff414cSEd Maste   return 0;
286*10ff414cSEd Maste }
287