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" 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