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