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/malformated 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 /* Move the result before free */ 104 cbor_item_t *result_item = context.root; 105 return result_item; 106 107 error: 108 result->error.position = result->read; 109 // debug_print("Failed with decoder error %d at %d\n", result->error.code, 110 // result->error.position); cbor_describe(stack.top->item, stdout); 111 /* Free the stack */ 112 while (stack.size > 0) { 113 cbor_decref(&stack.top->item); 114 _cbor_stack_pop(&stack); 115 } 116 return NULL; 117 } 118 119 static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) { 120 cbor_item_t *res; 121 switch (cbor_int_get_width(item)) { 122 case CBOR_INT_8: 123 res = cbor_build_uint8(cbor_get_uint8(item)); 124 break; 125 case CBOR_INT_16: 126 res = cbor_build_uint16(cbor_get_uint16(item)); 127 break; 128 case CBOR_INT_32: 129 res = cbor_build_uint32(cbor_get_uint32(item)); 130 break; 131 case CBOR_INT_64: 132 res = cbor_build_uint64(cbor_get_uint64(item)); 133 break; 134 default: 135 return NULL; 136 } 137 138 if (negative) cbor_mark_negint(res); 139 140 return res; 141 } 142 143 static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) { 144 switch (cbor_float_get_width(item)) { 145 case CBOR_FLOAT_0: 146 return cbor_build_ctrl(cbor_ctrl_value(item)); 147 case CBOR_FLOAT_16: 148 return cbor_build_float2(cbor_float_get_float2(item)); 149 case CBOR_FLOAT_32: 150 return cbor_build_float4(cbor_float_get_float4(item)); 151 case CBOR_FLOAT_64: 152 return cbor_build_float8(cbor_float_get_float8(item)); 153 } 154 155 return NULL; 156 } 157 158 cbor_item_t *cbor_copy(cbor_item_t *item) { 159 switch (cbor_typeof(item)) { 160 case CBOR_TYPE_UINT: 161 return _cbor_copy_int(item, false); 162 case CBOR_TYPE_NEGINT: 163 return _cbor_copy_int(item, true); 164 case CBOR_TYPE_BYTESTRING: 165 if (cbor_bytestring_is_definite(item)) { 166 return cbor_build_bytestring(cbor_bytestring_handle(item), 167 cbor_bytestring_length(item)); 168 } else { 169 cbor_item_t *res = cbor_new_indefinite_bytestring(); 170 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) 171 cbor_bytestring_add_chunk( 172 res, 173 cbor_move(cbor_copy(cbor_bytestring_chunks_handle(item)[i]))); 174 return res; 175 } 176 case CBOR_TYPE_STRING: 177 if (cbor_string_is_definite(item)) { 178 return cbor_build_stringn((const char *)cbor_string_handle(item), 179 cbor_string_length(item)); 180 } else { 181 cbor_item_t *res = cbor_new_indefinite_string(); 182 for (size_t i = 0; i < cbor_string_chunk_count(item); i++) 183 cbor_string_add_chunk( 184 res, cbor_move(cbor_copy(cbor_string_chunks_handle(item)[i]))); 185 return res; 186 } 187 case CBOR_TYPE_ARRAY: { 188 cbor_item_t *res; 189 if (cbor_array_is_definite(item)) 190 res = cbor_new_definite_array(cbor_array_size(item)); 191 else 192 res = cbor_new_indefinite_array(); 193 194 for (size_t i = 0; i < cbor_array_size(item); i++) 195 cbor_array_push( 196 res, cbor_move(cbor_copy(cbor_move(cbor_array_get(item, i))))); 197 return res; 198 } 199 case CBOR_TYPE_MAP: { 200 cbor_item_t *res; 201 if (cbor_map_is_definite(item)) 202 res = cbor_new_definite_map(cbor_map_size(item)); 203 else 204 res = cbor_new_indefinite_map(); 205 206 struct cbor_pair *it = cbor_map_handle(item); 207 for (size_t i = 0; i < cbor_map_size(item); i++) 208 cbor_map_add(res, (struct cbor_pair){ 209 .key = cbor_move(cbor_copy(it[i].key)), 210 .value = cbor_move(cbor_copy(it[i].value))}); 211 return res; 212 } 213 case CBOR_TYPE_TAG: 214 return cbor_build_tag( 215 cbor_tag_value(item), 216 cbor_move(cbor_copy(cbor_move(cbor_tag_item(item))))); 217 case CBOR_TYPE_FLOAT_CTRL: 218 return _cbor_copy_float_ctrl(item); 219 } 220 221 return NULL; 222 } 223 224 #if CBOR_PRETTY_PRINTER 225 226 #include <inttypes.h> 227 #include <locale.h> 228 #include <stdlib.h> 229 #include <wchar.h> 230 231 #define __STDC_FORMAT_MACROS 232 233 static int _pow(int b, int ex) { 234 if (ex == 0) return 1; 235 int res = b; 236 while (--ex > 0) res *= b; 237 return res; 238 } 239 240 static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) { 241 setlocale(LC_ALL, ""); 242 switch (cbor_typeof(item)) { 243 case CBOR_TYPE_UINT: { 244 fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " "); 245 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); 246 fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item)); 247 break; 248 }; 249 case CBOR_TYPE_NEGINT: { 250 fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " "); 251 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); 252 fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item)); 253 break; 254 }; 255 case CBOR_TYPE_BYTESTRING: { 256 fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " "); 257 if (cbor_bytestring_is_indefinite(item)) { 258 fprintf(out, "Indefinite, with %zu chunks:\n", 259 cbor_bytestring_chunk_count(item)); 260 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) 261 _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out, 262 indent + 4); 263 } else { 264 fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item)); 265 } 266 break; 267 }; 268 case CBOR_TYPE_STRING: { 269 fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " "); 270 if (cbor_string_is_indefinite(item)) { 271 fprintf(out, "Indefinite, with %zu chunks:\n", 272 cbor_string_chunk_count(item)); 273 for (size_t i = 0; i < cbor_string_chunk_count(item); i++) 274 _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out, 275 indent + 4); 276 } else { 277 fprintf(out, "Definite, length %zuB, %zu codepoints\n", 278 cbor_string_length(item), cbor_string_codepoint_count(item)); 279 /* Careful - this doesn't support multibyte characters! */ 280 /* Printing those is out of the scope of this demo :) */ 281 /* libICU is your friend */ 282 fprintf(out, "%*s", indent + 4, " "); 283 /* XXX: no null at the end -> confused vprintf */ 284 fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out); 285 fprintf(out, "\n"); 286 } 287 break; 288 }; 289 case CBOR_TYPE_ARRAY: { 290 fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " "); 291 if (cbor_array_is_definite(item)) { 292 fprintf(out, "Definite, size: %zu\n", cbor_array_size(item)); 293 } else { 294 fprintf(out, "Indefinite, size: %zu\n", cbor_array_size(item)); 295 } 296 297 for (size_t i = 0; i < cbor_array_size(item); i++) 298 _cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4); 299 break; 300 }; 301 case CBOR_TYPE_MAP: { 302 fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " "); 303 if (cbor_map_is_definite(item)) { 304 fprintf(out, "Definite, size: %zu\n", cbor_map_size(item)); 305 } else { 306 fprintf(out, "Indefinite, size: %zu\n", cbor_map_size(item)); 307 } 308 309 for (size_t i = 0; i < cbor_map_size(item); i++) { 310 _cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4); 311 _cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4); 312 } 313 break; 314 }; 315 case CBOR_TYPE_TAG: { 316 fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " "); 317 fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item)); 318 _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4); 319 break; 320 }; 321 case CBOR_TYPE_FLOAT_CTRL: { 322 fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " "); 323 if (cbor_float_ctrl_is_ctrl(item)) { 324 if (cbor_is_bool(item)) 325 fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false"); 326 else if (cbor_is_undef(item)) 327 fprintf(out, "Undefined\n"); 328 else if (cbor_is_null(item)) 329 fprintf(out, "Null\n"); 330 else 331 fprintf(out, "Simple value %d\n", cbor_ctrl_value(item)); 332 } else { 333 fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item))); 334 fprintf(out, "value: %lf\n", cbor_float_get_float(item)); 335 } 336 break; 337 }; 338 } 339 } 340 341 void cbor_describe(cbor_item_t *item, FILE *out) { 342 _cbor_nested_describe(item, out, 0); 343 } 344 345 #endif 346