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 "builder_callbacks.h" 9 10 #include <string.h> 11 12 #include "../arrays.h" 13 #include "../bytestrings.h" 14 #include "../common.h" 15 #include "../floats_ctrls.h" 16 #include "../ints.h" 17 #include "../maps.h" 18 #include "../strings.h" 19 #include "../tags.h" 20 #include "unicode.h" 21 22 // `_cbor_builder_append` takes ownership of `item`. If adding the item to 23 // parent container fails, `item` will be deallocated to prevent memory. 24 void _cbor_builder_append(cbor_item_t *item, 25 struct _cbor_decoder_context *ctx) { 26 if (ctx->stack->size == 0) { 27 /* Top level item */ 28 ctx->root = item; 29 return; 30 } 31 /* Part of a bigger structure */ 32 switch (ctx->stack->top->item->type) { 33 // Handle Arrays and Maps since they can contain subitems of any type. 34 // Byte/string construction from chunks is handled in the respective chunk 35 // handlers. 36 case CBOR_TYPE_ARRAY: { 37 if (cbor_array_is_definite(ctx->stack->top->item)) { 38 // We don't need an explicit check for whether the item still belongs 39 // into this array because if there are extra items, they will cause a 40 // syntax error when decoded. 41 CBOR_ASSERT(ctx->stack->top->subitems > 0); 42 // This should never happen since the definite array should be 43 // preallocated for the expected number of items. 44 if (!cbor_array_push(ctx->stack->top->item, item)) { 45 ctx->creation_failed = true; 46 cbor_decref(&item); 47 break; 48 } 49 cbor_decref(&item); 50 ctx->stack->top->subitems--; 51 if (ctx->stack->top->subitems == 0) { 52 cbor_item_t *stack_item = ctx->stack->top->item; 53 _cbor_stack_pop(ctx->stack); 54 _cbor_builder_append(stack_item, ctx); 55 } 56 } else { 57 /* Indefinite array, don't bother with subitems */ 58 if (!cbor_array_push(ctx->stack->top->item, item)) { 59 ctx->creation_failed = true; 60 } 61 cbor_decref(&item); 62 } 63 break; 64 } 65 case CBOR_TYPE_MAP: { 66 // Handle both definite and indefinite maps the same initially. 67 // Note: We use 0 and 1 subitems to distinguish between keys and values in 68 // indefinite items 69 if (ctx->stack->top->subitems % 2) { 70 // Odd record, this is a value. 71 ctx->creation_failed = 72 !_cbor_map_add_value(ctx->stack->top->item, item); 73 // Adding a value never fails since the memory is allocated when the 74 // key is added 75 CBOR_ASSERT(!ctx->creation_failed); 76 } else { 77 // Even record, this is a key. 78 if (!_cbor_map_add_key(ctx->stack->top->item, item)) { 79 ctx->creation_failed = true; 80 cbor_decref(&item); 81 break; 82 } 83 } 84 cbor_decref(&item); 85 if (cbor_map_is_definite(ctx->stack->top->item)) { 86 CBOR_ASSERT(ctx->stack->top->subitems > 0); 87 ctx->stack->top->subitems--; 88 if (ctx->stack->top->subitems == 0) { 89 cbor_item_t *map_entry = ctx->stack->top->item; 90 _cbor_stack_pop(ctx->stack); 91 _cbor_builder_append(map_entry, ctx); 92 } 93 } else { 94 ctx->stack->top->subitems ^= 95 1; /* Flip the indicator for indefinite items */ 96 } 97 break; 98 } 99 case CBOR_TYPE_TAG: { 100 CBOR_ASSERT(ctx->stack->top->subitems == 1); 101 cbor_tag_set_item(ctx->stack->top->item, item); 102 cbor_decref(&item); /* Give up on our reference */ 103 cbor_item_t *tagged_item = ctx->stack->top->item; 104 _cbor_stack_pop(ctx->stack); 105 _cbor_builder_append(tagged_item, ctx); 106 break; 107 } 108 // We have an item to append but nothing to append it to. 109 default: { 110 cbor_decref(&item); 111 ctx->syntax_error = true; 112 } 113 } 114 } 115 116 #define CHECK_RES(ctx, res) \ 117 do { \ 118 if (res == NULL) { \ 119 ctx->creation_failed = true; \ 120 return; \ 121 } \ 122 } while (0) 123 124 // Check that the length fits into size_t. If not, we cannot possibly allocate 125 // the required memory and should fail fast. 126 #define CHECK_LENGTH(ctx, length) \ 127 do { \ 128 if (length > SIZE_MAX) { \ 129 ctx->creation_failed = true; \ 130 return; \ 131 } \ 132 } while (0) 133 134 #define PUSH_CTX_STACK(ctx, res, subitems) \ 135 do { \ 136 if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \ 137 cbor_decref(&res); \ 138 ctx->creation_failed = true; \ 139 } \ 140 } while (0) 141 142 void cbor_builder_uint8_callback(void *context, uint8_t value) { 143 struct _cbor_decoder_context *ctx = context; 144 cbor_item_t *res = cbor_new_int8(); 145 CHECK_RES(ctx, res); 146 cbor_mark_uint(res); 147 cbor_set_uint8(res, value); 148 _cbor_builder_append(res, ctx); 149 } 150 151 void cbor_builder_uint16_callback(void *context, uint16_t value) { 152 struct _cbor_decoder_context *ctx = context; 153 cbor_item_t *res = cbor_new_int16(); 154 CHECK_RES(ctx, res); 155 cbor_mark_uint(res); 156 cbor_set_uint16(res, value); 157 _cbor_builder_append(res, ctx); 158 } 159 160 void cbor_builder_uint32_callback(void *context, uint32_t value) { 161 struct _cbor_decoder_context *ctx = context; 162 cbor_item_t *res = cbor_new_int32(); 163 CHECK_RES(ctx, res); 164 cbor_mark_uint(res); 165 cbor_set_uint32(res, value); 166 _cbor_builder_append(res, ctx); 167 } 168 169 void cbor_builder_uint64_callback(void *context, uint64_t value) { 170 struct _cbor_decoder_context *ctx = context; 171 cbor_item_t *res = cbor_new_int64(); 172 CHECK_RES(ctx, res); 173 cbor_mark_uint(res); 174 cbor_set_uint64(res, value); 175 _cbor_builder_append(res, ctx); 176 } 177 178 void cbor_builder_negint8_callback(void *context, uint8_t value) { 179 struct _cbor_decoder_context *ctx = context; 180 cbor_item_t *res = cbor_new_int8(); 181 CHECK_RES(ctx, res); 182 cbor_mark_negint(res); 183 cbor_set_uint8(res, value); 184 _cbor_builder_append(res, ctx); 185 } 186 187 void cbor_builder_negint16_callback(void *context, uint16_t value) { 188 struct _cbor_decoder_context *ctx = context; 189 cbor_item_t *res = cbor_new_int16(); 190 CHECK_RES(ctx, res); 191 cbor_mark_negint(res); 192 cbor_set_uint16(res, value); 193 _cbor_builder_append(res, ctx); 194 } 195 196 void cbor_builder_negint32_callback(void *context, uint32_t value) { 197 struct _cbor_decoder_context *ctx = context; 198 cbor_item_t *res = cbor_new_int32(); 199 CHECK_RES(ctx, res); 200 cbor_mark_negint(res); 201 cbor_set_uint32(res, value); 202 _cbor_builder_append(res, ctx); 203 } 204 205 void cbor_builder_negint64_callback(void *context, uint64_t value) { 206 struct _cbor_decoder_context *ctx = context; 207 cbor_item_t *res = cbor_new_int64(); 208 CHECK_RES(ctx, res); 209 cbor_mark_negint(res); 210 cbor_set_uint64(res, value); 211 _cbor_builder_append(res, ctx); 212 } 213 214 void cbor_builder_byte_string_callback(void *context, cbor_data data, 215 uint64_t length) { 216 struct _cbor_decoder_context *ctx = context; 217 CHECK_LENGTH(ctx, length); 218 unsigned char *new_handle = _cbor_malloc(length); 219 if (new_handle == NULL) { 220 ctx->creation_failed = true; 221 return; 222 } 223 224 memcpy(new_handle, data, length); 225 cbor_item_t *new_chunk = cbor_new_definite_bytestring(); 226 227 if (new_chunk == NULL) { 228 _cbor_free(new_handle); 229 ctx->creation_failed = true; 230 return; 231 } 232 233 cbor_bytestring_set_handle(new_chunk, new_handle, length); 234 235 // If an indef bytestring is on the stack, extend it (if it were closed, it 236 // would have been popped). Handle any syntax errors upstream. 237 if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item) && 238 cbor_bytestring_is_indefinite(ctx->stack->top->item)) { 239 if (!cbor_bytestring_add_chunk(ctx->stack->top->item, new_chunk)) { 240 ctx->creation_failed = true; 241 } 242 cbor_decref(&new_chunk); 243 } else { 244 _cbor_builder_append(new_chunk, ctx); 245 } 246 } 247 248 void cbor_builder_byte_string_start_callback(void *context) { 249 struct _cbor_decoder_context *ctx = context; 250 cbor_item_t *res = cbor_new_indefinite_bytestring(); 251 CHECK_RES(ctx, res); 252 PUSH_CTX_STACK(ctx, res, 0); 253 } 254 255 void cbor_builder_string_callback(void *context, cbor_data data, 256 uint64_t length) { 257 struct _cbor_decoder_context *ctx = context; 258 CHECK_LENGTH(ctx, length); 259 260 unsigned char *new_handle = _cbor_malloc(length); 261 if (new_handle == NULL) { 262 ctx->creation_failed = true; 263 return; 264 } 265 266 memcpy(new_handle, data, length); 267 cbor_item_t *new_chunk = cbor_new_definite_string(); 268 if (new_chunk == NULL) { 269 _cbor_free(new_handle); 270 ctx->creation_failed = true; 271 return; 272 } 273 cbor_string_set_handle(new_chunk, new_handle, length); 274 275 // If an indef string is on the stack, extend it (if it were closed, it would 276 // have been popped). Handle any syntax errors upstream. 277 if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) && 278 cbor_string_is_indefinite(ctx->stack->top->item)) { 279 if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) { 280 ctx->creation_failed = true; 281 } 282 cbor_decref(&new_chunk); 283 } else { 284 _cbor_builder_append(new_chunk, ctx); 285 } 286 } 287 288 void cbor_builder_string_start_callback(void *context) { 289 struct _cbor_decoder_context *ctx = context; 290 cbor_item_t *res = cbor_new_indefinite_string(); 291 CHECK_RES(ctx, res); 292 PUSH_CTX_STACK(ctx, res, 0); 293 } 294 295 void cbor_builder_array_start_callback(void *context, uint64_t size) { 296 struct _cbor_decoder_context *ctx = context; 297 CHECK_LENGTH(ctx, size); 298 cbor_item_t *res = cbor_new_definite_array(size); 299 CHECK_RES(ctx, res); 300 if (size > 0) { 301 PUSH_CTX_STACK(ctx, res, size); 302 } else { 303 _cbor_builder_append(res, ctx); 304 } 305 } 306 307 void cbor_builder_indef_array_start_callback(void *context) { 308 struct _cbor_decoder_context *ctx = context; 309 cbor_item_t *res = cbor_new_indefinite_array(); 310 CHECK_RES(ctx, res); 311 PUSH_CTX_STACK(ctx, res, 0); 312 } 313 314 void cbor_builder_indef_map_start_callback(void *context) { 315 struct _cbor_decoder_context *ctx = context; 316 cbor_item_t *res = cbor_new_indefinite_map(); 317 CHECK_RES(ctx, res); 318 PUSH_CTX_STACK(ctx, res, 0); 319 } 320 321 void cbor_builder_map_start_callback(void *context, uint64_t size) { 322 struct _cbor_decoder_context *ctx = context; 323 CHECK_LENGTH(ctx, size); 324 cbor_item_t *res = cbor_new_definite_map(size); 325 CHECK_RES(ctx, res); 326 if (size > 0) { 327 PUSH_CTX_STACK(ctx, res, size * 2); 328 } else { 329 _cbor_builder_append(res, ctx); 330 } 331 } 332 333 /** 334 * Is the (partially constructed) item indefinite? 335 */ 336 bool _cbor_is_indefinite(cbor_item_t *item) { 337 switch (item->type) { 338 case CBOR_TYPE_BYTESTRING: 339 return cbor_bytestring_is_indefinite(item); 340 case CBOR_TYPE_STRING: 341 return cbor_string_is_indefinite(item); 342 case CBOR_TYPE_ARRAY: 343 return cbor_array_is_indefinite(item); 344 case CBOR_TYPE_MAP: 345 return cbor_map_is_indefinite(item); 346 default: 347 // Should never happen since a non-nested item cannot be on top of the 348 // stack. 349 return false; 350 } 351 } 352 353 void cbor_builder_indef_break_callback(void *context) { 354 struct _cbor_decoder_context *ctx = context; 355 /* There must be an item to break out of*/ 356 if (ctx->stack->size > 0) { 357 cbor_item_t *item = ctx->stack->top->item; 358 if (_cbor_is_indefinite( 359 item) && /* Only indefinite items can be terminated by 0xFF */ 360 /* Special case: we cannot append up if an indefinite map is incomplete 361 (we are expecting a value). */ 362 (item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) { 363 _cbor_stack_pop(ctx->stack); 364 _cbor_builder_append(item, ctx); 365 return; 366 } 367 } 368 369 ctx->syntax_error = true; 370 } 371 372 void cbor_builder_float2_callback(void *context, float value) { 373 struct _cbor_decoder_context *ctx = context; 374 cbor_item_t *res = cbor_new_float2(); 375 CHECK_RES(ctx, res); 376 cbor_set_float2(res, value); 377 _cbor_builder_append(res, ctx); 378 } 379 380 void cbor_builder_float4_callback(void *context, float value) { 381 struct _cbor_decoder_context *ctx = context; 382 cbor_item_t *res = cbor_new_float4(); 383 CHECK_RES(ctx, res); 384 cbor_set_float4(res, value); 385 _cbor_builder_append(res, ctx); 386 } 387 388 void cbor_builder_float8_callback(void *context, double value) { 389 struct _cbor_decoder_context *ctx = context; 390 cbor_item_t *res = cbor_new_float8(); 391 CHECK_RES(ctx, res); 392 cbor_set_float8(res, value); 393 _cbor_builder_append(res, ctx); 394 } 395 396 void cbor_builder_null_callback(void *context) { 397 struct _cbor_decoder_context *ctx = context; 398 cbor_item_t *res = cbor_new_null(); 399 CHECK_RES(ctx, res); 400 _cbor_builder_append(res, ctx); 401 } 402 403 void cbor_builder_undefined_callback(void *context) { 404 struct _cbor_decoder_context *ctx = context; 405 cbor_item_t *res = cbor_new_undef(); 406 CHECK_RES(ctx, res); 407 _cbor_builder_append(res, ctx); 408 } 409 410 void cbor_builder_boolean_callback(void *context, bool value) { 411 struct _cbor_decoder_context *ctx = context; 412 cbor_item_t *res = cbor_build_bool(value); 413 CHECK_RES(ctx, res); 414 _cbor_builder_append(res, ctx); 415 } 416 417 void cbor_builder_tag_callback(void *context, uint64_t value) { 418 struct _cbor_decoder_context *ctx = context; 419 cbor_item_t *res = cbor_new_tag(value); 420 CHECK_RES(ctx, res); 421 PUSH_CTX_STACK(ctx, res, 1); 422 } 423