libcbor 0.12.0
libcbor is a C library for parsing and generating CBOR, the general-purpose schema-less binary data format.
Loading...
Searching...
No Matches
serialization.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014-2020 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"
19
20size_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);
26 return cbor_serialize_negint(item, buffer, buffer_size);
28 return cbor_serialize_bytestring(item, buffer, buffer_size);
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);
38 return cbor_serialize_float_ctrl(item, buffer, buffer_size);
39 default:
41 return 0;
42 }
43}
44
46const uint64_t kMaxEmbeddedInt = 23;
47
50size_t _cbor_encoded_header_size(uint64_t size) {
51 if (size <= kMaxEmbeddedInt)
52 return 1;
53 else if (size <= UINT8_MAX)
54 return 2;
55 else if (size <= UINT16_MAX)
56 return 3;
57 else if (size <= UINT32_MAX)
58 return 5;
59 else
60 return 9;
61}
62
63size_t cbor_serialized_size(const cbor_item_t* item) {
64 switch (cbor_typeof(item)) {
65 case CBOR_TYPE_UINT:
67 switch (cbor_int_get_width(item)) {
68 case CBOR_INT_8:
69 if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;
70 return 2;
71 case CBOR_INT_16:
72 return 3;
73 case CBOR_INT_32:
74 return 5;
75 case CBOR_INT_64:
76 return 9;
77 default:
79 return 0;
80 }
81 // Note: We do not _cbor_safe_signaling_add zero-length definite strings,
82 // they would cause zeroes to propagate. All other items are at least one
83 // byte.
86 size_t header_size =
88 if (cbor_bytestring_length(item) == 0) return header_size;
89 return _cbor_safe_signaling_add(header_size,
91 }
92 size_t indef_bytestring_size = 2; // Leading byte + break
94 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
95 indef_bytestring_size = _cbor_safe_signaling_add(
96 indef_bytestring_size, cbor_serialized_size(chunks[i]));
97 }
98 return indef_bytestring_size;
99 }
100 case CBOR_TYPE_STRING: {
101 if (cbor_string_is_definite(item)) {
102 size_t header_size =
104 if (cbor_string_length(item) == 0) return header_size;
105 return _cbor_safe_signaling_add(header_size, cbor_string_length(item));
106 }
107 size_t indef_string_size = 2; // Leading byte + break
108 cbor_item_t** chunks = cbor_string_chunks_handle(item);
109 for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
110 indef_string_size = _cbor_safe_signaling_add(
111 indef_string_size, cbor_serialized_size(chunks[i]));
112 }
113 return indef_string_size;
114 }
115 case CBOR_TYPE_ARRAY: {
116 size_t array_size = cbor_array_is_definite(item)
118 : 2; // Leading byte + break
119 cbor_item_t** items = cbor_array_handle(item);
120 for (size_t i = 0; i < cbor_array_size(item); i++) {
121 array_size = _cbor_safe_signaling_add(array_size,
122 cbor_serialized_size(items[i]));
123 }
124 return array_size;
125 }
126 case CBOR_TYPE_MAP: {
127 size_t map_size = cbor_map_is_definite(item)
129 : 2; // Leading byte + break
130 struct cbor_pair* items = cbor_map_handle(item);
131 for (size_t i = 0; i < cbor_map_size(item); i++) {
132 map_size = _cbor_safe_signaling_add(
133 map_size,
135 cbor_serialized_size(items[i].value)));
136 }
137 return map_size;
138 }
139 case CBOR_TYPE_TAG: {
143 }
145 switch (cbor_float_get_width(item)) {
146 case CBOR_FLOAT_0:
148 case CBOR_FLOAT_16:
149 return 3;
150 case CBOR_FLOAT_32:
151 return 5;
152 case CBOR_FLOAT_64:
153 return 9;
154 default:
156 return 0;
157 }
158 default:
160 return 0;
161 }
162}
163
164size_t cbor_serialize_alloc(const cbor_item_t* item, unsigned char** buffer,
165 size_t* buffer_size) {
166 *buffer = NULL;
167 size_t serialized_size = cbor_serialized_size(item);
168 if (serialized_size == 0) {
169 if (buffer_size != NULL) *buffer_size = 0;
170 return 0;
171 }
172 *buffer = _cbor_malloc(serialized_size);
173 if (*buffer == NULL) {
174 if (buffer_size != NULL) *buffer_size = 0;
175 return 0;
176 }
177
178 size_t written = cbor_serialize(item, *buffer, serialized_size);
179 CBOR_ASSERT(written == serialized_size);
180 if (buffer_size != NULL) *buffer_size = serialized_size;
181 return written;
182}
183
184size_t cbor_serialize_uint(const cbor_item_t* item, unsigned char* buffer,
185 size_t buffer_size) {
187 // cppcheck-suppress missingReturn
188 switch (cbor_int_get_width(item)) {
189 case CBOR_INT_8:
190 return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
191 case CBOR_INT_16:
192 return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);
193 case CBOR_INT_32:
194 return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
195 case CBOR_INT_64:
196 return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
197 default:
199 return 0;
200 }
201}
202
203size_t cbor_serialize_negint(const cbor_item_t* item, unsigned char* buffer,
204 size_t buffer_size) {
206 // cppcheck-suppress missingReturn
207 switch (cbor_int_get_width(item)) {
208 case CBOR_INT_8:
209 return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
210 case CBOR_INT_16:
211 return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);
212 case CBOR_INT_32:
213 return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
214 case CBOR_INT_64:
215 return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
216 default:
218 return 0;
219 }
220}
221
222size_t cbor_serialize_bytestring(const cbor_item_t* item, unsigned char* buffer,
223 size_t buffer_size) {
225 if (cbor_bytestring_is_definite(item)) {
226 size_t length = cbor_bytestring_length(item);
227 size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
228 if (written > 0 && (buffer_size - written >= length)) {
229 memcpy(buffer + written, cbor_bytestring_handle(item), length);
230 return written + length;
231 }
232 return 0;
233 } else {
235 size_t chunk_count = cbor_bytestring_chunk_count(item);
236 size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
237 if (written == 0) return 0;
238
240 for (size_t i = 0; i < chunk_count; i++) {
241 size_t chunk_written = cbor_serialize_bytestring(
242 chunks[i], buffer + written, buffer_size - written);
243 if (chunk_written == 0) return 0;
244 written += chunk_written;
245 }
246
247 size_t break_written =
248 cbor_encode_break(buffer + written, buffer_size - written);
249 if (break_written == 0) return 0;
250 return written + break_written;
251 }
252}
253
254size_t cbor_serialize_string(const cbor_item_t* item, unsigned char* buffer,
255 size_t buffer_size) {
257 if (cbor_string_is_definite(item)) {
258 size_t length = cbor_string_length(item);
259 size_t written = cbor_encode_string_start(length, buffer, buffer_size);
260 if (written && (buffer_size - written >= length)) {
261 memcpy(buffer + written, cbor_string_handle(item), length);
262 return written + length;
263 }
264 return 0;
265 } else {
267 size_t chunk_count = cbor_string_chunk_count(item);
268 size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
269 if (written == 0) return 0;
270
271 cbor_item_t** chunks = cbor_string_chunks_handle(item);
272 for (size_t i = 0; i < chunk_count; i++) {
273 size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,
274 buffer_size - written);
275 if (chunk_written == 0) return 0;
276 written += chunk_written;
277 }
278
279 size_t break_written =
280 cbor_encode_break(buffer + written, buffer_size - written);
281 if (break_written == 0) return 0;
282 return written + break_written;
283 }
284}
285
286size_t cbor_serialize_array(const cbor_item_t* item, unsigned char* buffer,
287 size_t buffer_size) {
289 size_t size = cbor_array_size(item), written = 0;
290 cbor_item_t** handle = cbor_array_handle(item);
291 if (cbor_array_is_definite(item)) {
292 written = cbor_encode_array_start(size, buffer, buffer_size);
293 } else {
295 written = cbor_encode_indef_array_start(buffer, buffer_size);
296 }
297 if (written == 0) return 0;
298
299 for (size_t i = 0; i < size; i++) {
300 size_t item_written =
301 cbor_serialize(*(handle++), buffer + written, buffer_size - written);
302 if (item_written == 0) return 0;
303 written += item_written;
304 }
305
306 if (cbor_array_is_definite(item)) {
307 return written;
308 } else {
310 size_t break_written =
311 cbor_encode_break(buffer + written, buffer_size - written);
312 if (break_written == 0) return 0;
313 return written + break_written;
314 }
315}
316
317size_t cbor_serialize_map(const cbor_item_t* item, unsigned char* buffer,
318 size_t buffer_size) {
320 size_t size = cbor_map_size(item), written = 0;
321 struct cbor_pair* handle = cbor_map_handle(item);
322
323 if (cbor_map_is_definite(item)) {
324 written = cbor_encode_map_start(size, buffer, buffer_size);
325 } else {
327 written = cbor_encode_indef_map_start(buffer, buffer_size);
328 }
329 if (written == 0) return 0;
330
331 for (size_t i = 0; i < size; i++) {
332 size_t item_written =
333 cbor_serialize(handle->key, buffer + written, buffer_size - written);
334 if (item_written == 0) {
335 return 0;
336 }
337 written += item_written;
338 item_written = cbor_serialize((handle++)->value, buffer + written,
339 buffer_size - written);
340 if (item_written == 0) return 0;
341 written += item_written;
342 }
343
344 if (cbor_map_is_definite(item)) {
345 return written;
346 } else {
348 size_t break_written =
349 cbor_encode_break(buffer + written, buffer_size - written);
350 if (break_written == 0) return 0;
351 return written + break_written;
352 }
353}
354
355size_t cbor_serialize_tag(const cbor_item_t* item, unsigned char* buffer,
356 size_t buffer_size) {
358 size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
359 if (written == 0) return 0;
360
361 size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),
362 buffer + written, buffer_size - written);
363 if (item_written == 0) return 0;
364 return written + item_written;
365}
366
367size_t cbor_serialize_float_ctrl(const cbor_item_t* item, unsigned char* buffer,
368 size_t buffer_size) {
370 // cppcheck-suppress missingReturn
371 switch (cbor_float_get_width(item)) {
372 case CBOR_FLOAT_0:
373 /* CTRL - special treatment */
374 return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);
375 case CBOR_FLOAT_16:
376 return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);
377 case CBOR_FLOAT_32:
378 return cbor_encode_single(cbor_float_get_float4(item), buffer,
379 buffer_size);
380 case CBOR_FLOAT_64:
381 return cbor_encode_double(cbor_float_get_float8(item), buffer,
382 buffer_size);
383 default:
385 return 0;
386 }
387}
_cbor_malloc_t _cbor_malloc
Definition allocators.c:10
bool cbor_array_is_indefinite(const cbor_item_t *item)
Is the array indefinite?
Definition arrays.c:87
size_t cbor_array_size(const cbor_item_t *item)
Get the number of members.
Definition arrays.c:12
cbor_item_t ** cbor_array_handle(const cbor_item_t *item)
Get the array contents.
Definition arrays.c:92
bool cbor_array_is_definite(const cbor_item_t *item)
Is the array definite?
Definition arrays.c:82
bool cbor_bytestring_is_definite(const cbor_item_t *item)
Is the byte string definite?
Definition bytestrings.c:22
bool cbor_bytestring_is_indefinite(const cbor_item_t *item)
Is the byte string indefinite?
Definition bytestrings.c:27
size_t cbor_bytestring_length(const cbor_item_t *item)
Returns the length of the binary data.
Definition bytestrings.c:12
cbor_item_t ** cbor_bytestring_chunks_handle(const cbor_item_t *item)
Get the handle to the array of chunks.
Definition bytestrings.c:80
size_t cbor_bytestring_chunk_count(const cbor_item_t *item)
Get the number of chunks this string consist of.
Definition bytestrings.c:86
unsigned char * cbor_bytestring_handle(const cbor_item_t *item)
Get the handle to the binary data.
Definition bytestrings.c:17
bool cbor_isa_string(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:34
bool cbor_isa_negint(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:26
bool cbor_isa_tag(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:46
cbor_item_t * cbor_move(cbor_item_t *item)
Provides CPP-like move construct.
Definition common.c:158
bool cbor_isa_uint(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:22
bool cbor_isa_float_ctrl(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:50
bool cbor_isa_array(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:38
cbor_type cbor_typeof(const cbor_item_t *item)
Get the type of the item.
Definition common.c:54
bool cbor_isa_bytestring(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:30
bool cbor_isa_map(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:42
#define _CBOR_UNREACHABLE
Definition common.h:99
#define CBOR_ASSERT(e)
Definition common.h:73
@ CBOR_TYPE_MAP
5 - maps
Definition data.h:35
@ CBOR_TYPE_FLOAT_CTRL
7 - decimals and special values (true, false, nil, ...)
Definition data.h:39
@ CBOR_TYPE_TAG
6 - tags
Definition data.h:37
@ CBOR_TYPE_UINT
0 - positive integers
Definition data.h:25
@ CBOR_TYPE_BYTESTRING
2 - byte strings
Definition data.h:29
@ CBOR_TYPE_STRING
3 - strings
Definition data.h:31
@ CBOR_TYPE_NEGINT
1 - negative integers
Definition data.h:27
@ CBOR_TYPE_ARRAY
4 - arrays
Definition data.h:33
@ CBOR_FLOAT_32
Single float.
Definition data.h:71
@ CBOR_FLOAT_16
Half float.
Definition data.h:69
@ CBOR_FLOAT_64
Double.
Definition data.h:73
@ CBOR_FLOAT_0
Internal use - ctrl and special values.
Definition data.h:67
@ CBOR_INT_16
Definition data.h:60
@ CBOR_INT_8
Definition data.h:59
@ CBOR_INT_64
Definition data.h:62
@ CBOR_INT_32
Definition data.h:61
size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:44
size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:211
size_t cbor_encode_map_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:103
size_t cbor_encode_tag(uint64_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:112
size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:54
size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size)
Definition encoding.c:108
size_t cbor_encode_array_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:93
size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:14
size_t cbor_encode_half(float value, unsigned char *buffer, size_t buffer_size)
Encodes a half-precision float.
Definition encoding.c:130
size_t cbor_encode_indef_bytestring_start(unsigned char *buffer, size_t buffer_size)
Definition encoding.c:78
size_t cbor_encode_double(double value, unsigned char *buffer, size_t buffer_size)
Encodes a double precision float.
Definition encoding.c:194
size_t cbor_encode_indef_array_start(unsigned char *buffer, size_t buffer_size)
Definition encoding.c:98
size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:19
size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:29
size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:49
size_t cbor_encode_string_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:83
size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:24
size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:39
size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition encoding.c:64
size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size)
Definition encoding.c:207
size_t cbor_encode_single(float value, unsigned char *buffer, size_t buffer_size)
Encodes a single precision float.
Definition encoding.c:180
size_t cbor_encode_indef_string_start(unsigned char *buffer, size_t buffer_size)
Definition encoding.c:88
cbor_float_width cbor_float_get_width(const cbor_item_t *item)
Get the float width.
double cbor_float_get_float8(const cbor_item_t *item)
Get a double precision float.
uint8_t cbor_ctrl_value(const cbor_item_t *item)
Reads the control value.
float cbor_float_get_float2(const cbor_item_t *item)
Get a half precision float.
float cbor_float_get_float4(const cbor_item_t *item)
Get a single precision float.
uint32_t cbor_get_uint32(const cbor_item_t *item)
Extracts the integer value.
Definition ints.c:27
uint16_t cbor_get_uint16(const cbor_item_t *item)
Extracts the integer value.
Definition ints.c:21
uint8_t cbor_get_uint8(const cbor_item_t *item)
Extracts the integer value.
Definition ints.c:15
cbor_int_width cbor_int_get_width(const cbor_item_t *item)
Queries the integer width.
Definition ints.c:10
uint64_t cbor_get_uint64(const cbor_item_t *item)
Extracts the integer value.
Definition ints.c:33
bool cbor_map_is_definite(const cbor_item_t *item)
Is this map definite?
Definition maps.c:113
struct cbor_pair * cbor_map_handle(const cbor_item_t *item)
Get the pairs storage.
Definition maps.c:122
size_t cbor_map_size(const cbor_item_t *item)
Get the number of pairs.
Definition maps.c:11
bool cbor_map_is_indefinite(const cbor_item_t *item)
Is this map indefinite?
Definition maps.c:118
size_t _cbor_safe_signaling_add(size_t a, size_t b)
Adds a and b, propagating zeros and returning 0 on overflow.
size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a string.
size_t cbor_serialized_size(const cbor_item_t *item)
Compute the length (in bytes) of the item when serialized using cbor_serialize.
size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a.
size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize the given item.
size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a tag.
size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a negint.
size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a bytestring.
size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize an array.
size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize an uint.
size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a map.
size_t _cbor_encoded_header_size(uint64_t size)
How many bytes will a tag for a nested item of a given size take when encoded.
size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer, size_t *buffer_size)
Serialize the given item, allocating buffers as needed.
const uint64_t kMaxEmbeddedInt
Largest integer that can be encoded as embedded in the item leading byte.
size_t cbor_string_length(const cbor_item_t *item)
Returns the length of the underlying string in bytes.
Definition strings.c:122
bool cbor_string_is_indefinite(const cbor_item_t *item)
Is the string indefinite?
Definition strings.c:142
bool cbor_string_is_definite(const cbor_item_t *item)
Is the string definite?
Definition strings.c:137
cbor_item_t ** cbor_string_chunks_handle(const cbor_item_t *item)
Get the handle to the array of chunks.
Definition strings.c:83
unsigned char * cbor_string_handle(const cbor_item_t *item)
Get the handle to the underlying string.
Definition strings.c:127
size_t cbor_string_chunk_count(const cbor_item_t *item)
Get the number of chunks this string consist of.
Definition strings.c:89
The item handle.
Definition data.h:171
Simple pair of items for use in maps.
Definition data.h:201
cbor_item_t * value
Definition data.h:202
cbor_item_t * key
Definition data.h:202
cbor_item_t * cbor_tag_item(const cbor_item_t *tag)
Get the tagged item (what the tag points to).
Definition tags.c:23
uint64_t cbor_tag_value(const cbor_item_t *tag)
Get the tag value.
Definition tags.c:28