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 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); 27 case CBOR_TYPE_BYTESTRING: 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); 37 case CBOR_TYPE_FLOAT_CTRL: 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, unsigned char **buffer, 45 size_t *buffer_size) { 46 size_t bfr_size = 32; 47 unsigned char *bfr = _CBOR_MALLOC(bfr_size), *tmp_bfr; 48 if (bfr == NULL) { 49 return 0; 50 } 51 52 size_t written; 53 54 /* This is waaay too optimistic - figure out something smarter (eventually) */ 55 while ((written = cbor_serialize(item, bfr, bfr_size)) == 0) { 56 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, bfr_size)) { 57 _CBOR_FREE(bfr); 58 return 0; 59 } 60 61 tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2); 62 63 if (tmp_bfr == NULL) { 64 _CBOR_FREE(bfr); 65 return 0; 66 } 67 bfr = tmp_bfr; 68 } 69 *buffer = bfr; 70 *buffer_size = bfr_size; 71 return written; 72 } 73 74 size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer, 75 size_t buffer_size) { 76 assert(cbor_isa_uint(item)); 77 switch (cbor_int_get_width(item)) { 78 case CBOR_INT_8: 79 return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size); 80 case CBOR_INT_16: 81 return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size); 82 case CBOR_INT_32: 83 return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size); 84 case CBOR_INT_64: 85 return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size); 86 default: 87 return 0; 88 } 89 } 90 91 size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer, 92 size_t buffer_size) { 93 assert(cbor_isa_negint(item)); 94 switch (cbor_int_get_width(item)) { 95 case CBOR_INT_8: 96 return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size); 97 case CBOR_INT_16: 98 return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size); 99 case CBOR_INT_32: 100 return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size); 101 case CBOR_INT_64: 102 return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size); 103 default: 104 return 0; 105 } 106 } 107 108 size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer, 109 size_t buffer_size) { 110 assert(cbor_isa_bytestring(item)); 111 if (cbor_bytestring_is_definite(item)) { 112 size_t length = cbor_bytestring_length(item); 113 size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size); 114 if (written && (buffer_size - written >= length)) { 115 memcpy(buffer + written, cbor_bytestring_handle(item), length); 116 return written + length; 117 } else 118 return 0; 119 } else { 120 assert(cbor_bytestring_is_indefinite(item)); 121 size_t chunk_count = cbor_bytestring_chunk_count(item); 122 size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size); 123 124 if (written == 0) return 0; 125 126 cbor_item_t **chunks = cbor_bytestring_chunks_handle(item); 127 for (size_t i = 0; i < chunk_count; i++) { 128 size_t chunk_written = cbor_serialize_bytestring( 129 chunks[i], buffer + written, buffer_size - written); 130 if (chunk_written == 0) 131 return 0; 132 else 133 written += chunk_written; 134 } 135 if (cbor_encode_break(buffer + written, buffer_size - written) > 0) 136 return written + 1; 137 else 138 return 0; 139 } 140 } 141 142 size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer, 143 size_t buffer_size) { 144 assert(cbor_isa_string(item)); 145 if (cbor_string_is_definite(item)) { 146 size_t length = cbor_string_length(item); 147 size_t written = cbor_encode_string_start(length, buffer, buffer_size); 148 if (written && (buffer_size - written >= length)) { 149 memcpy(buffer + written, cbor_string_handle(item), length); 150 return written + length; 151 } else 152 return 0; 153 } else { 154 assert(cbor_string_is_indefinite(item)); 155 size_t chunk_count = cbor_string_chunk_count(item); 156 size_t written = cbor_encode_indef_string_start(buffer, buffer_size); 157 158 if (written == 0) return 0; 159 160 cbor_item_t **chunks = cbor_string_chunks_handle(item); 161 for (size_t i = 0; i < chunk_count; i++) { 162 size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written, 163 buffer_size - written); 164 if (chunk_written == 0) 165 return 0; 166 else 167 written += chunk_written; 168 } 169 if (cbor_encode_break(buffer + written, buffer_size - written) > 0) 170 return written + 1; 171 else 172 return 0; 173 } 174 } 175 176 size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer, 177 size_t buffer_size) { 178 assert(cbor_isa_array(item)); 179 size_t size = cbor_array_size(item), written = 0; 180 cbor_item_t **handle = cbor_array_handle(item); 181 if (cbor_array_is_definite(item)) { 182 written = cbor_encode_array_start(size, buffer, buffer_size); 183 } else { 184 assert(cbor_array_is_indefinite(item)); 185 written = cbor_encode_indef_array_start(buffer, buffer_size); 186 } 187 if (written == 0) return 0; 188 189 size_t item_written; 190 for (size_t i = 0; i < size; i++) { 191 item_written = 192 cbor_serialize(*(handle++), buffer + written, buffer_size - written); 193 if (item_written == 0) 194 return 0; 195 else 196 written += item_written; 197 } 198 199 if (cbor_array_is_definite(item)) { 200 return written; 201 } else { 202 assert(cbor_array_is_indefinite(item)); 203 item_written = cbor_encode_break(buffer + written, buffer_size - written); 204 if (item_written == 0) 205 return 0; 206 else 207 return written + 1; 208 } 209 } 210 211 size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer, 212 size_t buffer_size) { 213 assert(cbor_isa_map(item)); 214 size_t size = cbor_map_size(item), written = 0; 215 struct cbor_pair *handle = cbor_map_handle(item); 216 217 if (cbor_map_is_definite(item)) { 218 written = cbor_encode_map_start(size, buffer, buffer_size); 219 } else { 220 assert(cbor_map_is_indefinite(item)); 221 written = cbor_encode_indef_map_start(buffer, buffer_size); 222 } 223 if (written == 0) return 0; 224 225 size_t item_written; 226 for (size_t i = 0; i < size; i++) { 227 item_written = 228 cbor_serialize(handle->key, buffer + written, buffer_size - written); 229 if (item_written == 0) 230 return 0; 231 else 232 written += item_written; 233 item_written = cbor_serialize((handle++)->value, buffer + written, 234 buffer_size - written); 235 if (item_written == 0) 236 return 0; 237 else 238 written += item_written; 239 } 240 241 if (cbor_map_is_definite(item)) { 242 return written; 243 } else { 244 assert(cbor_map_is_indefinite(item)); 245 item_written = cbor_encode_break(buffer + written, buffer_size - written); 246 if (item_written == 0) 247 return 0; 248 else 249 return written + 1; 250 } 251 } 252 253 size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer, 254 size_t buffer_size) { 255 assert(cbor_isa_tag(item)); 256 size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size); 257 if (written == 0) return 0; 258 259 size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)), 260 buffer + written, buffer_size - written); 261 if (item_written == 0) 262 return 0; 263 else 264 return written + item_written; 265 } 266 267 size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer, 268 size_t buffer_size) { 269 assert(cbor_isa_float_ctrl(item)); 270 switch (cbor_float_get_width(item)) { 271 case CBOR_FLOAT_0: 272 /* CTRL - special treatment */ 273 return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size); 274 case CBOR_FLOAT_16: 275 return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size); 276 case CBOR_FLOAT_32: 277 return cbor_encode_single(cbor_float_get_float4(item), buffer, 278 buffer_size); 279 case CBOR_FLOAT_64: 280 return cbor_encode_double(cbor_float_get_float8(item), buffer, 281 buffer_size); 282 } 283 284 /* Should never happen - make the compiler happy */ 285 return 0; 286 } 287