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