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