libcbor  0.5.0
libcbor is a C library for parsing and generating CBOR, the general-purpose schema-less binary data format.
serialization.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2017 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 "encoding.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 "internal/memory_utils.h"
18 #include <string.h>
19 
20 size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
21 {
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);
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);
38  return cbor_serialize_float_ctrl(item, buffer, buffer_size);
39  default:
40  return 0;
41  }
42 }
43 
44 size_t cbor_serialize_alloc(const cbor_item_t * item,
45  unsigned char ** buffer,
46  size_t * buffer_size)
47 {
48  size_t bfr_size = 32;
49  unsigned char * bfr = _CBOR_MALLOC(bfr_size), * tmp_bfr;
50  if (bfr == NULL) {
51  return 0;
52  }
53 
54  size_t written;
55 
56  /* This is waaay too optimistic - figure out something smarter (eventually) */
57  while ((written = cbor_serialize(item, bfr, bfr_size)) == 0) {
58  if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, bfr_size)) {
59  _CBOR_FREE(bfr);
60  return 0;
61  }
62 
63  tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2);
64 
65  if (tmp_bfr == NULL) {
66  _CBOR_FREE(bfr);
67  return 0;
68  }
69  bfr = tmp_bfr;
70  }
71  *buffer = bfr;
72  *buffer_size = bfr_size;
73  return written;
74 }
75 
76 size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
77 {
78  assert(cbor_isa_uint(item));
79  switch (cbor_int_get_width(item)) {
80  case CBOR_INT_8:
81  return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
82  case CBOR_INT_16:
83  return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);
84  case CBOR_INT_32:
85  return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
86  case CBOR_INT_64:
87  return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
88  default:
89  return 0;
90  }
91 }
92 
93 size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
94 {
95  assert(cbor_isa_negint(item));
96  switch (cbor_int_get_width(item)) {
97  case CBOR_INT_8:
98  return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
99  case CBOR_INT_16:
100  return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);
101  case CBOR_INT_32:
102  return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
103  case CBOR_INT_64:
104  return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
105  default:
106  return 0;
107  }
108 }
109 
110 size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
111 {
112  assert(cbor_isa_bytestring(item));
113  if (cbor_bytestring_is_definite(item)) {
114  size_t length = cbor_bytestring_length(item);
115  size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
116  if (written && (buffer_size - written >= length)) {
117  memcpy(buffer + written, cbor_bytestring_handle(item), length);
118  return written + length;
119  } else
120  return 0;
121  } else {
122  assert(cbor_bytestring_is_indefinite(item));
123  size_t chunk_count = cbor_bytestring_chunk_count(item);
124  size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
125 
126  if (written == 0)
127  return 0;
128 
130  for (size_t i = 0; i < chunk_count; i++) {
131  size_t chunk_written = cbor_serialize_bytestring(chunks[i], buffer + written, buffer_size - written);
132  if (chunk_written == 0)
133  return 0;
134  else
135  written += chunk_written;
136  }
137  if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
138  return written + 1;
139  else
140  return 0;
141  }
142 }
143 
144 size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
145 {
146  assert(cbor_isa_string(item));
147  if (cbor_string_is_definite(item)) {
148  size_t length = cbor_string_length(item);
149  size_t written = cbor_encode_string_start(length, buffer, buffer_size);
150  if (written && (buffer_size - written >= length)) {
151  memcpy(buffer + written, cbor_string_handle(item), length);
152  return written + length;
153  } else
154  return 0;
155  } else {
156  assert(cbor_string_is_indefinite(item));
157  size_t chunk_count = cbor_string_chunk_count(item);
158  size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
159 
160  if (written == 0)
161  return 0;
162 
163  cbor_item_t **chunks = cbor_string_chunks_handle(item);
164  for (size_t i = 0; i < chunk_count; i++) {
165  size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written, buffer_size - written);
166  if (chunk_written == 0)
167  return 0;
168  else
169  written += chunk_written;
170  }
171  if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
172  return written + 1;
173  else
174  return 0;
175  }
176 }
177 
178 size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
179 {
180  assert(cbor_isa_array(item));
181  size_t size = cbor_array_size(item),
182  written = 0;
183  cbor_item_t **handle = cbor_array_handle(item);
184  if (cbor_array_is_definite(item)) {
185  written = cbor_encode_array_start(size, buffer, buffer_size);
186  } else {
187  assert(cbor_array_is_indefinite(item));
188  written = cbor_encode_indef_array_start(buffer, buffer_size);
189  }
190  if (written == 0)
191  return 0;
192 
193  size_t item_written;
194  for (size_t i = 0; i < size; i++) {
195  item_written = cbor_serialize(*(handle++), buffer + written, buffer_size - written);
196  if (item_written == 0)
197  return 0;
198  else
199  written += item_written;
200  }
201 
202  if (cbor_array_is_definite(item)) {
203  return written;
204  } else {
205  assert(cbor_array_is_indefinite(item));
206  item_written = cbor_encode_break(buffer + written, buffer_size - written);
207  if (item_written == 0)
208  return 0;
209  else
210  return written + 1;
211  }
212 }
213 
214 size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
215 {
216  assert(cbor_isa_map(item));
217  size_t size = cbor_map_size(item),
218  written = 0;
219  struct cbor_pair * handle = cbor_map_handle(item);
220 
221  if (cbor_map_is_definite(item)) {
222  written = cbor_encode_map_start(size, buffer, buffer_size);
223  } else {
224  assert(cbor_map_is_indefinite(item));
225  written = cbor_encode_indef_map_start(buffer, buffer_size);
226  }
227  if (written == 0)
228  return 0;
229 
230  size_t item_written;
231  for (size_t i = 0; i < size; i++) {
232  item_written = cbor_serialize(handle->key, buffer + written, buffer_size - written);
233  if (item_written == 0)
234  return 0;
235  else
236  written += item_written;
237  item_written = cbor_serialize((handle++)->value, buffer + written, buffer_size - written);
238  if (item_written == 0)
239  return 0;
240  else
241  written += item_written;
242  }
243 
244  if (cbor_map_is_definite(item)) {
245  return written;
246  } else {
247  assert(cbor_map_is_indefinite(item));
248  item_written = cbor_encode_break(buffer + written, buffer_size - written);
249  if (item_written == 0)
250  return 0;
251  else
252  return written + 1;
253  }
254 }
255 
256 size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
257 {
258  assert(cbor_isa_tag(item));
259  size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
260  if (written == 0)
261  return 0;
262 
263  size_t item_written = cbor_serialize(cbor_tag_item(item), buffer + written, buffer_size - written);
264  if (item_written == 0)
265  return 0;
266  else
267  return written + item_written;
268 }
269 
270 size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
271 {
272  assert(cbor_isa_float_ctrl(item));
273  switch (cbor_float_get_width(item)) {
274  case CBOR_FLOAT_0:
275  /* CTRL - special treatment */
276  return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);
277  case CBOR_FLOAT_16:
278  return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);
279  case CBOR_FLOAT_32:
280  return cbor_encode_single(cbor_float_get_float4(item), buffer, buffer_size);
281  case CBOR_FLOAT_64:
282  return cbor_encode_double(cbor_float_get_float8(item), buffer, buffer_size);
283  }
284 
285  /* Should never happen - make the compiler happy */
286  return 0;
287 }
size_t cbor_encode_map_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:101
size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:178
bool cbor_bytestring_is_definite(const cbor_item_t *item)
Is the byte string definite?
Definition: bytestrings.c:24
6 - tags
Definition: data.h:31
3 - strings
Definition: data.h:28
size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize an uint.
Definition: serialization.c:76
size_t cbor_encode_half(float value, unsigned char *buffer, size_t buffer_size)
Encodes a half-precision float.
Definition: encoding.c:131
cbor_int_width cbor_int_get_width(const cbor_item_t *item)
Queries the integer width.
Definition: ints.c:10
2 - byte strings
Definition: data.h:27
Internal use - ctrl and special values.
Definition: data.h:55
size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a map.
unsigned char * cbor_string_handle(const cbor_item_t *item)
Get the handle to the underlying string.
Definition: strings.c:112
size_t cbor_encode_indef_array_start(unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:96
size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a bytestring.
bool cbor_isa_negint(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:23
cbor_item_t * value
Definition: data.h:180
size_t cbor_encode_string_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:81
bool cbor_isa_string(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:33
size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:47
size_t cbor_bytestring_chunk_count(const cbor_item_t *item)
Get the number of chunks this string consist of.
Definition: bytestrings.c:87
cbor_item_t ** cbor_string_chunks_handle(const cbor_item_t *item)
Get the handle to the array of chunks.
Definition: strings.c:67
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.
Definition: serialization.c:44
bool cbor_isa_bytestring(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:28
size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:183
size_t cbor_map_size(const cbor_item_t *item)
Get the number of pairs.
Definition: maps.c:11
cbor_item_t ** cbor_bytestring_chunks_handle(const cbor_item_t *item)
Get the handle to the array of chunks.
Definition: bytestrings.c:80
bool cbor_bytestring_is_indefinite(const cbor_item_t *item)
Is the byte string indefinite?
Definition: bytestrings.c:30
4 - arrays
Definition: data.h:29
cbor_item_t * cbor_tag_item(const cbor_item_t *item)
Get the tagged item.
Definition: tags.c:22
cbor_item_t * key
Definition: data.h:180
size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:37
size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a string.
size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:26
7 - decimals and special values (true, false, nil, ...)
Definition: data.h:32
uint32_t cbor_get_uint32(const cbor_item_t *item)
Extracts the integer value.
Definition: ints.c:30
#define _CBOR_FREE
Definition: common.h:86
#define _CBOR_MALLOC
Definition: common.h:84
bool cbor_map_is_indefinite(const cbor_item_t *item)
Is this map indefinite?
Definition: maps.c:132
Simple pair of items for use in maps.
Definition: data.h:179
bool cbor_array_is_definite(const cbor_item_t *item)
Is the array definite?
Definition: arrays.c:88
Double.
Definition: data.h:58
uint16_t cbor_get_uint16(const cbor_item_t *item)
Extracts the integer value.
Definition: ints.c:23
Half float.
Definition: data.h:56
size_t cbor_encode_single(float value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:167
size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:106
size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a tag.
size_t cbor_encode_double(double value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:173
size_t cbor_string_chunk_count(const cbor_item_t *item)
Get the number of chunks this string consist of.
Definition: strings.c:74
size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a.
size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize an array.
size_t cbor_array_size(const cbor_item_t *item)
Get the number of members.
Definition: arrays.c:12
0 - positive integers
Definition: data.h:25
size_t cbor_encode_array_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:91
size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:11
size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:16
uint8_t cbor_get_uint8(const cbor_item_t *item)
Extracts the integer value.
Definition: ints.c:16
float cbor_float_get_float4(const cbor_item_t *item)
Get a single precision float.
Definition: floats_ctrls.c:38
uint64_t cbor_get_uint64(const cbor_item_t *item)
Extracts the integer value.
Definition: ints.c:37
uint8_t cbor_ctrl_value(const cbor_item_t *item)
Reads the control value.
Definition: floats_ctrls.c:18
uint64_t cbor_tag_value(const cbor_item_t *item)
Get tag value.
Definition: tags.c:28
cbor_float_width cbor_float_get_width(const cbor_item_t *item)
Get the float width.
Definition: floats_ctrls.c:12
bool cbor_isa_float_ctrl(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:53
bool cbor_isa_array(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:38
bool cbor_isa_map(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:43
bool cbor_map_is_definite(const cbor_item_t *item)
Is this map definite?
Definition: maps.c:126
float cbor_float_get_float2(const cbor_item_t *item)
Get a half precision float.
Definition: floats_ctrls.c:31
bool cbor_isa_uint(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:18
double cbor_float_get_float8(const cbor_item_t *item)
Get a double precision float.
Definition: floats_ctrls.c:45
bool cbor_isa_tag(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:48
size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:52
size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:21
cbor_type cbor_typeof(const cbor_item_t *item)
Get the type of the item.
Definition: common.c:59
bool cbor_string_is_definite(const cbor_item_t *item)
Is the string definite?
Definition: strings.c:124
unsigned char * cbor_bytestring_handle(const cbor_item_t *item)
Get the handle to the binary data.
Definition: bytestrings.c:18
#define _CBOR_REALLOC
Definition: common.h:85
size_t cbor_encode_indef_string_start(unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:86
size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize the given item.
Definition: serialization.c:20
size_t cbor_string_length(const cbor_item_t *item)
Returns the length of the underlying string.
Definition: strings.c:106
size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:62
bool _cbor_safe_to_multiply(size_t a, size_t b)
Can a and b be multiplied without overflowing size_t?
Definition: memory_utils.c:25
size_t cbor_encode_indef_bytestring_start(unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:76
The item handle.
Definition: data.h:149
size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:42
1 - negative integers
Definition: data.h:26
struct cbor_pair * cbor_map_handle(const cbor_item_t *item)
Get the pairs storage.
Definition: maps.c:137
bool cbor_array_is_indefinite(const cbor_item_t *item)
Is the array indefinite?
Definition: arrays.c:94
size_t cbor_bytestring_length(const cbor_item_t *item)
Returns the length of the binary data.
Definition: bytestrings.c:12
size_t cbor_encode_tag(uint64_t value, unsigned char *buffer, size_t buffer_size)
Definition: encoding.c:111
size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size)
Serialize a negint.
Definition: serialization.c:93
cbor_item_t ** cbor_array_handle(const cbor_item_t *item)
Get the array contents.
Definition: arrays.c:100
5 - maps
Definition: data.h:30
Single float.
Definition: data.h:57
bool cbor_string_is_indefinite(const cbor_item_t *item)
Is the string indefinite?
Definition: strings.c:130