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