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 "cbor.h" 9 #include "cbor/internal/builder_callbacks.h" 10 #include "cbor/internal/loaders.h" 11 12 cbor_item_t *cbor_load(cbor_data source, size_t source_size, 13 struct cbor_load_result *result) { 14 /* Context stack */ 15 static struct cbor_callbacks callbacks = { 16 .uint8 = &cbor_builder_uint8_callback, 17 .uint16 = &cbor_builder_uint16_callback, 18 .uint32 = &cbor_builder_uint32_callback, 19 .uint64 = &cbor_builder_uint64_callback, 20 21 .negint8 = &cbor_builder_negint8_callback, 22 .negint16 = &cbor_builder_negint16_callback, 23 .negint32 = &cbor_builder_negint32_callback, 24 .negint64 = &cbor_builder_negint64_callback, 25 26 .byte_string = &cbor_builder_byte_string_callback, 27 .byte_string_start = &cbor_builder_byte_string_start_callback, 28 29 .string = &cbor_builder_string_callback, 30 .string_start = &cbor_builder_string_start_callback, 31 32 .array_start = &cbor_builder_array_start_callback, 33 .indef_array_start = &cbor_builder_indef_array_start_callback, 34 35 .map_start = &cbor_builder_map_start_callback, 36 .indef_map_start = &cbor_builder_indef_map_start_callback, 37 38 .tag = &cbor_builder_tag_callback, 39 40 .null = &cbor_builder_null_callback, 41 .undefined = &cbor_builder_undefined_callback, 42 .boolean = &cbor_builder_boolean_callback, 43 .float2 = &cbor_builder_float2_callback, 44 .float4 = &cbor_builder_float4_callback, 45 .float8 = &cbor_builder_float8_callback, 46 .indef_break = &cbor_builder_indef_break_callback}; 47 48 if (source_size == 0) { 49 result->error.code = CBOR_ERR_NODATA; 50 return NULL; 51 } 52 struct _cbor_stack stack = _cbor_stack_init(); 53 54 /* Target for callbacks */ 55 struct _cbor_decoder_context context = (struct _cbor_decoder_context){ 56 .stack = &stack, .creation_failed = false, .syntax_error = false}; 57 struct cbor_decoder_result decode_result; 58 *result = 59 (struct cbor_load_result){.read = 0, .error = {.code = CBOR_ERR_NONE}}; 60 61 do { 62 if (source_size > result->read) { /* Check for overflows */ 63 decode_result = 64 cbor_stream_decode(source + result->read, source_size - result->read, 65 &callbacks, &context); 66 } else { 67 result->error = (struct cbor_error){.code = CBOR_ERR_NOTENOUGHDATA, 68 .position = result->read}; 69 goto error; 70 } 71 72 switch (decode_result.status) { 73 case CBOR_DECODER_FINISHED: 74 /* Everything OK */ 75 { 76 result->read += decode_result.read; 77 break; 78 } 79 case CBOR_DECODER_NEDATA: 80 /* Data length doesn't match MTB expectation */ 81 { 82 result->error.code = CBOR_ERR_NOTENOUGHDATA; 83 goto error; 84 } 85 case CBOR_DECODER_ERROR: 86 /* Reserved/malformed item */ 87 { 88 result->error.code = CBOR_ERR_MALFORMATED; 89 goto error; 90 } 91 } 92 93 if (context.creation_failed) { 94 /* Most likely unsuccessful allocation - our callback has failed */ 95 result->error.code = CBOR_ERR_MEMERROR; 96 goto error; 97 } else if (context.syntax_error) { 98 result->error.code = CBOR_ERR_SYNTAXERROR; 99 goto error; 100 } 101 } while (stack.size > 0); 102 103 return context.root; 104 105 error: 106 result->error.position = result->read; 107 // debug_print("Failed with decoder error %d at %d\n", result->error.code, 108 // result->error.position); cbor_describe(stack.top->item, stdout); 109 /* Free the stack */ 110 while (stack.size > 0) { 111 cbor_decref(&stack.top->item); 112 _cbor_stack_pop(&stack); 113 } 114 return NULL; 115 } 116 117 static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) { 118 cbor_item_t *res; 119 switch (cbor_int_get_width(item)) { 120 case CBOR_INT_8: 121 res = cbor_build_uint8(cbor_get_uint8(item)); 122 break; 123 case CBOR_INT_16: 124 res = cbor_build_uint16(cbor_get_uint16(item)); 125 break; 126 case CBOR_INT_32: 127 res = cbor_build_uint32(cbor_get_uint32(item)); 128 break; 129 case CBOR_INT_64: 130 res = cbor_build_uint64(cbor_get_uint64(item)); 131 break; 132 } 133 134 if (negative) cbor_mark_negint(res); 135 136 return res; 137 } 138 139 static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) { 140 // cppcheck-suppress missingReturn 141 switch (cbor_float_get_width(item)) { 142 case CBOR_FLOAT_0: 143 return cbor_build_ctrl(cbor_ctrl_value(item)); 144 case CBOR_FLOAT_16: 145 return cbor_build_float2(cbor_float_get_float2(item)); 146 case CBOR_FLOAT_32: 147 return cbor_build_float4(cbor_float_get_float4(item)); 148 case CBOR_FLOAT_64: 149 return cbor_build_float8(cbor_float_get_float8(item)); 150 } 151 } 152 153 cbor_item_t *cbor_copy(cbor_item_t *item) { 154 // cppcheck-suppress missingReturn 155 switch (cbor_typeof(item)) { 156 case CBOR_TYPE_UINT: 157 return _cbor_copy_int(item, false); 158 case CBOR_TYPE_NEGINT: 159 return _cbor_copy_int(item, true); 160 case CBOR_TYPE_BYTESTRING: 161 if (cbor_bytestring_is_definite(item)) { 162 return cbor_build_bytestring(cbor_bytestring_handle(item), 163 cbor_bytestring_length(item)); 164 } else { 165 cbor_item_t *res = cbor_new_indefinite_bytestring(); 166 if (res == NULL) { 167 return NULL; 168 } 169 170 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) { 171 cbor_item_t *chunk_copy = 172 cbor_copy(cbor_bytestring_chunks_handle(item)[i]); 173 if (chunk_copy == NULL) { 174 cbor_decref(&res); 175 return NULL; 176 } 177 if (!cbor_bytestring_add_chunk(res, chunk_copy)) { 178 cbor_decref(&chunk_copy); 179 cbor_decref(&res); 180 return NULL; 181 } 182 cbor_decref(&chunk_copy); 183 } 184 return res; 185 } 186 case CBOR_TYPE_STRING: 187 if (cbor_string_is_definite(item)) { 188 return cbor_build_stringn((const char *)cbor_string_handle(item), 189 cbor_string_length(item)); 190 } else { 191 cbor_item_t *res = cbor_new_indefinite_string(); 192 if (res == NULL) { 193 return NULL; 194 } 195 196 for (size_t i = 0; i < cbor_string_chunk_count(item); i++) { 197 cbor_item_t *chunk_copy = 198 cbor_copy(cbor_string_chunks_handle(item)[i]); 199 if (chunk_copy == NULL) { 200 cbor_decref(&res); 201 return NULL; 202 } 203 if (!cbor_string_add_chunk(res, chunk_copy)) { 204 cbor_decref(&chunk_copy); 205 cbor_decref(&res); 206 return NULL; 207 } 208 cbor_decref(&chunk_copy); 209 } 210 return res; 211 } 212 case CBOR_TYPE_ARRAY: { 213 cbor_item_t *res; 214 if (cbor_array_is_definite(item)) { 215 res = cbor_new_definite_array(cbor_array_size(item)); 216 } else { 217 res = cbor_new_indefinite_array(); 218 } 219 if (res == NULL) { 220 return NULL; 221 } 222 223 for (size_t i = 0; i < cbor_array_size(item); i++) { 224 cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i))); 225 if (entry_copy == NULL) { 226 cbor_decref(&res); 227 return NULL; 228 } 229 if (!cbor_array_push(res, entry_copy)) { 230 cbor_decref(&entry_copy); 231 cbor_decref(&res); 232 return NULL; 233 } 234 cbor_decref(&entry_copy); 235 } 236 return res; 237 } 238 case CBOR_TYPE_MAP: { 239 cbor_item_t *res; 240 if (cbor_map_is_definite(item)) { 241 res = cbor_new_definite_map(cbor_map_size(item)); 242 } else { 243 res = cbor_new_indefinite_map(); 244 } 245 if (res == NULL) { 246 return NULL; 247 } 248 249 struct cbor_pair *it = cbor_map_handle(item); 250 for (size_t i = 0; i < cbor_map_size(item); i++) { 251 cbor_item_t *key_copy = cbor_copy(it[i].key); 252 if (key_copy == NULL) { 253 cbor_decref(&res); 254 return NULL; 255 } 256 cbor_item_t *value_copy = cbor_copy(it[i].value); 257 if (value_copy == NULL) { 258 cbor_decref(&res); 259 cbor_decref(&key_copy); 260 return NULL; 261 } 262 if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy, 263 .value = value_copy})) { 264 cbor_decref(&res); 265 cbor_decref(&key_copy); 266 cbor_decref(&value_copy); 267 return NULL; 268 } 269 cbor_decref(&key_copy); 270 cbor_decref(&value_copy); 271 } 272 return res; 273 } 274 case CBOR_TYPE_TAG: { 275 cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item))); 276 if (item_copy == NULL) { 277 return NULL; 278 } 279 cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy); 280 cbor_decref(&item_copy); 281 return tag; 282 } 283 case CBOR_TYPE_FLOAT_CTRL: 284 return _cbor_copy_float_ctrl(item); 285 } 286 } 287 288 #if CBOR_PRETTY_PRINTER 289 290 #include <inttypes.h> 291 #include <locale.h> 292 #include <stdlib.h> 293 #include <wchar.h> 294 295 #define __STDC_FORMAT_MACROS 296 297 static int _pow(int b, int ex) { 298 if (ex == 0) return 1; 299 int res = b; 300 while (--ex > 0) res *= b; 301 return res; 302 } 303 304 static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) { 305 setlocale(LC_ALL, ""); 306 switch (cbor_typeof(item)) { 307 case CBOR_TYPE_UINT: { 308 fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " "); 309 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); 310 fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item)); 311 break; 312 } 313 case CBOR_TYPE_NEGINT: { 314 fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " "); 315 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); 316 fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item)); 317 break; 318 } 319 case CBOR_TYPE_BYTESTRING: { 320 fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " "); 321 if (cbor_bytestring_is_indefinite(item)) { 322 fprintf(out, "Indefinite, with %zu chunks:\n", 323 cbor_bytestring_chunk_count(item)); 324 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) 325 _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out, 326 indent + 4); 327 } else { 328 fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item)); 329 } 330 break; 331 } 332 case CBOR_TYPE_STRING: { 333 fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " "); 334 if (cbor_string_is_indefinite(item)) { 335 fprintf(out, "Indefinite, with %zu chunks:\n", 336 cbor_string_chunk_count(item)); 337 for (size_t i = 0; i < cbor_string_chunk_count(item); i++) 338 _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out, 339 indent + 4); 340 } else { 341 fprintf(out, "Definite, length %zuB, %zu codepoints\n", 342 cbor_string_length(item), cbor_string_codepoint_count(item)); 343 /* Careful - this doesn't support multibyte characters! */ 344 /* Printing those is out of the scope of this demo :) */ 345 /* libICU is your friend */ 346 fprintf(out, "%*s", indent + 4, " "); 347 /* XXX: no null at the end -> confused vprintf */ 348 fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out); 349 fprintf(out, "\n"); 350 } 351 break; 352 } 353 case CBOR_TYPE_ARRAY: { 354 fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " "); 355 if (cbor_array_is_definite(item)) { 356 fprintf(out, "Definite, size: %zu\n", cbor_array_size(item)); 357 } else { 358 fprintf(out, "Indefinite, size: %zu\n", cbor_array_size(item)); 359 } 360 361 for (size_t i = 0; i < cbor_array_size(item); i++) 362 _cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4); 363 break; 364 } 365 case CBOR_TYPE_MAP: { 366 fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " "); 367 if (cbor_map_is_definite(item)) { 368 fprintf(out, "Definite, size: %zu\n", cbor_map_size(item)); 369 } else { 370 fprintf(out, "Indefinite, size: %zu\n", cbor_map_size(item)); 371 } 372 373 for (size_t i = 0; i < cbor_map_size(item); i++) { 374 _cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4); 375 _cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4); 376 } 377 break; 378 } 379 case CBOR_TYPE_TAG: { 380 fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " "); 381 fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item)); 382 _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4); 383 break; 384 } 385 case CBOR_TYPE_FLOAT_CTRL: { 386 fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " "); 387 if (cbor_float_ctrl_is_ctrl(item)) { 388 if (cbor_is_bool(item)) 389 fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false"); 390 else if (cbor_is_undef(item)) 391 fprintf(out, "Undefined\n"); 392 else if (cbor_is_null(item)) 393 fprintf(out, "Null\n"); 394 else 395 fprintf(out, "Simple value %d\n", cbor_ctrl_value(item)); 396 } else { 397 fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item))); 398 fprintf(out, "value: %lf\n", cbor_float_get_float(item)); 399 } 400 break; 401 } 402 } 403 } 404 405 void cbor_describe(cbor_item_t *item, FILE *out) { 406 _cbor_nested_describe(item, out, 0); 407 } 408 409 #endif 410