Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libcbor/src/cbor/serialization.c
39562 views
1
/*
2
* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>
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
20
size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
21
size_t buffer_size) {
22
// cppcheck-suppress missingReturn
23
switch (cbor_typeof(item)) {
24
case CBOR_TYPE_UINT:
25
return cbor_serialize_uint(item, buffer, buffer_size);
26
case CBOR_TYPE_NEGINT:
27
return cbor_serialize_negint(item, buffer, buffer_size);
28
case CBOR_TYPE_BYTESTRING:
29
return cbor_serialize_bytestring(item, buffer, buffer_size);
30
case CBOR_TYPE_STRING:
31
return cbor_serialize_string(item, buffer, buffer_size);
32
case CBOR_TYPE_ARRAY:
33
return cbor_serialize_array(item, buffer, buffer_size);
34
case CBOR_TYPE_MAP:
35
return cbor_serialize_map(item, buffer, buffer_size);
36
case CBOR_TYPE_TAG:
37
return cbor_serialize_tag(item, buffer, buffer_size);
38
case CBOR_TYPE_FLOAT_CTRL:
39
return cbor_serialize_float_ctrl(item, buffer, buffer_size);
40
}
41
}
42
43
/** Largest integer that can be encoded as embedded in the item leading byte. */
44
const uint64_t kMaxEmbeddedInt = 23;
45
46
/** How many bytes will a tag for a nested item of a given `size` take when
47
* encoded.*/
48
size_t _cbor_encoded_header_size(uint64_t size) {
49
if (size <= kMaxEmbeddedInt)
50
return 1;
51
else if (size <= UINT8_MAX)
52
return 2;
53
else if (size <= UINT16_MAX)
54
return 3;
55
else if (size <= UINT32_MAX)
56
return 5;
57
else
58
return 9;
59
}
60
61
size_t cbor_serialized_size(const cbor_item_t *item) {
62
// cppcheck-suppress missingReturn
63
switch (cbor_typeof(item)) {
64
case CBOR_TYPE_UINT:
65
case CBOR_TYPE_NEGINT:
66
switch (cbor_int_get_width(item)) {
67
case CBOR_INT_8:
68
if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;
69
return 2;
70
case CBOR_INT_16:
71
return 3;
72
case CBOR_INT_32:
73
return 5;
74
case CBOR_INT_64:
75
return 9;
76
}
77
// Note: We do not _cbor_safe_signaling_add zero-length definite strings,
78
// they would cause zeroes to propagate. All other items are at least one
79
// byte.
80
case CBOR_TYPE_BYTESTRING: {
81
if (cbor_bytestring_is_definite(item)) {
82
size_t header_size =
83
_cbor_encoded_header_size(cbor_bytestring_length(item));
84
if (cbor_bytestring_length(item) == 0) return header_size;
85
return _cbor_safe_signaling_add(header_size,
86
cbor_bytestring_length(item));
87
}
88
size_t indef_bytestring_size = 2; // Leading byte + break
89
cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
90
for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
91
indef_bytestring_size = _cbor_safe_signaling_add(
92
indef_bytestring_size, cbor_serialized_size(chunks[i]));
93
}
94
return indef_bytestring_size;
95
}
96
case CBOR_TYPE_STRING: {
97
if (cbor_string_is_definite(item)) {
98
size_t header_size =
99
_cbor_encoded_header_size(cbor_string_length(item));
100
if (cbor_string_length(item) == 0) return header_size;
101
return _cbor_safe_signaling_add(header_size, cbor_string_length(item));
102
}
103
size_t indef_string_size = 2; // Leading byte + break
104
cbor_item_t **chunks = cbor_string_chunks_handle(item);
105
for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
106
indef_string_size = _cbor_safe_signaling_add(
107
indef_string_size, cbor_serialized_size(chunks[i]));
108
}
109
return indef_string_size;
110
}
111
case CBOR_TYPE_ARRAY: {
112
size_t array_size = cbor_array_is_definite(item)
113
? _cbor_encoded_header_size(cbor_array_size(item))
114
: 2; // Leading byte + break
115
cbor_item_t **items = cbor_array_handle(item);
116
for (size_t i = 0; i < cbor_array_size(item); i++) {
117
array_size = _cbor_safe_signaling_add(array_size,
118
cbor_serialized_size(items[i]));
119
}
120
return array_size;
121
}
122
case CBOR_TYPE_MAP: {
123
size_t map_size = cbor_map_is_definite(item)
124
? _cbor_encoded_header_size(cbor_map_size(item))
125
: 2; // Leading byte + break
126
struct cbor_pair *items = cbor_map_handle(item);
127
for (size_t i = 0; i < cbor_map_size(item); i++) {
128
map_size = _cbor_safe_signaling_add(
129
map_size,
130
_cbor_safe_signaling_add(cbor_serialized_size(items[i].key),
131
cbor_serialized_size(items[i].value)));
132
}
133
return map_size;
134
}
135
case CBOR_TYPE_TAG: {
136
return _cbor_safe_signaling_add(
137
_cbor_encoded_header_size(cbor_tag_value(item)),
138
cbor_serialized_size(cbor_move(cbor_tag_item(item))));
139
}
140
case CBOR_TYPE_FLOAT_CTRL:
141
switch (cbor_float_get_width(item)) {
142
case CBOR_FLOAT_0:
143
return _cbor_encoded_header_size(cbor_ctrl_value(item));
144
case CBOR_FLOAT_16:
145
return 3;
146
case CBOR_FLOAT_32:
147
return 5;
148
case CBOR_FLOAT_64:
149
return 9;
150
}
151
}
152
}
153
154
size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
155
size_t *buffer_size) {
156
*buffer = NULL;
157
size_t serialized_size = cbor_serialized_size(item);
158
if (serialized_size == 0) {
159
if (buffer_size != NULL) *buffer_size = 0;
160
return 0;
161
}
162
*buffer = _cbor_malloc(serialized_size);
163
if (*buffer == NULL) {
164
if (buffer_size != NULL) *buffer_size = 0;
165
return 0;
166
}
167
168
size_t written = cbor_serialize(item, *buffer, serialized_size);
169
CBOR_ASSERT(written == serialized_size);
170
if (buffer_size != NULL) *buffer_size = serialized_size;
171
return written;
172
}
173
174
size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
175
size_t buffer_size) {
176
CBOR_ASSERT(cbor_isa_uint(item));
177
// cppcheck-suppress missingReturn
178
switch (cbor_int_get_width(item)) {
179
case CBOR_INT_8:
180
return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
181
case CBOR_INT_16:
182
return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);
183
case CBOR_INT_32:
184
return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
185
case CBOR_INT_64:
186
return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
187
}
188
}
189
190
size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
191
size_t buffer_size) {
192
CBOR_ASSERT(cbor_isa_negint(item));
193
// cppcheck-suppress missingReturn
194
switch (cbor_int_get_width(item)) {
195
case CBOR_INT_8:
196
return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
197
case CBOR_INT_16:
198
return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);
199
case CBOR_INT_32:
200
return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
201
case CBOR_INT_64:
202
return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
203
}
204
}
205
206
size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer,
207
size_t buffer_size) {
208
CBOR_ASSERT(cbor_isa_bytestring(item));
209
if (cbor_bytestring_is_definite(item)) {
210
size_t length = cbor_bytestring_length(item);
211
size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
212
if (written > 0 && (buffer_size - written >= length)) {
213
memcpy(buffer + written, cbor_bytestring_handle(item), length);
214
return written + length;
215
}
216
return 0;
217
} else {
218
CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
219
size_t chunk_count = cbor_bytestring_chunk_count(item);
220
size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
221
if (written == 0) return 0;
222
223
cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
224
for (size_t i = 0; i < chunk_count; i++) {
225
size_t chunk_written = cbor_serialize_bytestring(
226
chunks[i], buffer + written, buffer_size - written);
227
if (chunk_written == 0) return 0;
228
written += chunk_written;
229
}
230
231
size_t break_written =
232
cbor_encode_break(buffer + written, buffer_size - written);
233
if (break_written == 0) return 0;
234
return written + break_written;
235
}
236
}
237
238
size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,
239
size_t buffer_size) {
240
CBOR_ASSERT(cbor_isa_string(item));
241
if (cbor_string_is_definite(item)) {
242
size_t length = cbor_string_length(item);
243
size_t written = cbor_encode_string_start(length, buffer, buffer_size);
244
if (written && (buffer_size - written >= length)) {
245
memcpy(buffer + written, cbor_string_handle(item), length);
246
return written + length;
247
}
248
return 0;
249
} else {
250
CBOR_ASSERT(cbor_string_is_indefinite(item));
251
size_t chunk_count = cbor_string_chunk_count(item);
252
size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
253
if (written == 0) return 0;
254
255
cbor_item_t **chunks = cbor_string_chunks_handle(item);
256
for (size_t i = 0; i < chunk_count; i++) {
257
size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,
258
buffer_size - written);
259
if (chunk_written == 0) return 0;
260
written += chunk_written;
261
}
262
263
size_t break_written =
264
cbor_encode_break(buffer + written, buffer_size - written);
265
if (break_written == 0) return 0;
266
return written + break_written;
267
}
268
}
269
270
size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,
271
size_t buffer_size) {
272
CBOR_ASSERT(cbor_isa_array(item));
273
size_t size = cbor_array_size(item), written = 0;
274
cbor_item_t **handle = cbor_array_handle(item);
275
if (cbor_array_is_definite(item)) {
276
written = cbor_encode_array_start(size, buffer, buffer_size);
277
} else {
278
CBOR_ASSERT(cbor_array_is_indefinite(item));
279
written = cbor_encode_indef_array_start(buffer, buffer_size);
280
}
281
if (written == 0) return 0;
282
283
for (size_t i = 0; i < size; i++) {
284
size_t item_written =
285
cbor_serialize(*(handle++), buffer + written, buffer_size - written);
286
if (item_written == 0) return 0;
287
written += item_written;
288
}
289
290
if (cbor_array_is_definite(item)) {
291
return written;
292
} else {
293
CBOR_ASSERT(cbor_array_is_indefinite(item));
294
size_t break_written =
295
cbor_encode_break(buffer + written, buffer_size - written);
296
if (break_written == 0) return 0;
297
return written + break_written;
298
}
299
}
300
301
size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,
302
size_t buffer_size) {
303
CBOR_ASSERT(cbor_isa_map(item));
304
size_t size = cbor_map_size(item), written = 0;
305
struct cbor_pair *handle = cbor_map_handle(item);
306
307
if (cbor_map_is_definite(item)) {
308
written = cbor_encode_map_start(size, buffer, buffer_size);
309
} else {
310
CBOR_ASSERT(cbor_map_is_indefinite(item));
311
written = cbor_encode_indef_map_start(buffer, buffer_size);
312
}
313
if (written == 0) return 0;
314
315
for (size_t i = 0; i < size; i++) {
316
size_t item_written =
317
cbor_serialize(handle->key, buffer + written, buffer_size - written);
318
if (item_written == 0) {
319
return 0;
320
}
321
written += item_written;
322
item_written = cbor_serialize((handle++)->value, buffer + written,
323
buffer_size - written);
324
if (item_written == 0) return 0;
325
written += item_written;
326
}
327
328
if (cbor_map_is_definite(item)) {
329
return written;
330
} else {
331
CBOR_ASSERT(cbor_map_is_indefinite(item));
332
size_t break_written =
333
cbor_encode_break(buffer + written, buffer_size - written);
334
if (break_written == 0) return 0;
335
return written + break_written;
336
}
337
}
338
339
size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,
340
size_t buffer_size) {
341
CBOR_ASSERT(cbor_isa_tag(item));
342
size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
343
if (written == 0) return 0;
344
345
size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),
346
buffer + written, buffer_size - written);
347
if (item_written == 0) return 0;
348
return written + item_written;
349
}
350
351
size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
352
size_t buffer_size) {
353
CBOR_ASSERT(cbor_isa_float_ctrl(item));
354
// cppcheck-suppress missingReturn
355
switch (cbor_float_get_width(item)) {
356
case CBOR_FLOAT_0:
357
/* CTRL - special treatment */
358
return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);
359
case CBOR_FLOAT_16:
360
return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);
361
case CBOR_FLOAT_32:
362
return cbor_encode_single(cbor_float_get_float4(item), buffer,
363
buffer_size);
364
case CBOR_FLOAT_64:
365
return cbor_encode_double(cbor_float_get_float8(item), buffer,
366
buffer_size);
367
}
368
}
369
370