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 if (!_cbor_map_add_value(ctx->stack->top->item, item)) { 72 ctx->creation_failed = true; 73 cbor_decref(&item); 74 break; 75 } 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 struct _cbor_unicode_status unicode_status; 260 uint64_t codepoint_count = 261 _cbor_unicode_codepoint_count(data, length, &unicode_status); 262 263 if (unicode_status.status != _CBOR_UNICODE_OK) { 264 ctx->syntax_error = true; 265 return; 266 } 267 CBOR_ASSERT(codepoint_count <= length); 268 269 unsigned char *new_handle = _cbor_malloc(length); 270 271 if (new_handle == NULL) { 272 ctx->creation_failed = true; 273 return; 274 } 275 276 memcpy(new_handle, data, length); 277 cbor_item_t *new_chunk = cbor_new_definite_string(); 278 if (new_chunk == NULL) { 279 _cbor_free(new_handle); 280 ctx->creation_failed = true; 281 return; 282 } 283 cbor_string_set_handle(new_chunk, new_handle, length); 284 new_chunk->metadata.string_metadata.codepoint_count = codepoint_count; 285 286 // If an indef string is on the stack, extend it (if it were closed, it would 287 // have been popped). Handle any syntax errors upstream. 288 if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) && 289 cbor_string_is_indefinite(ctx->stack->top->item)) { 290 if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) { 291 ctx->creation_failed = true; 292 } 293 cbor_decref(&new_chunk); 294 } else { 295 _cbor_builder_append(new_chunk, ctx); 296 } 297 } 298 299 void cbor_builder_string_start_callback(void *context) { 300 struct _cbor_decoder_context *ctx = context; 301 cbor_item_t *res = cbor_new_indefinite_string(); 302 CHECK_RES(ctx, res); 303 PUSH_CTX_STACK(ctx, res, 0); 304 } 305 306 void cbor_builder_array_start_callback(void *context, uint64_t size) { 307 struct _cbor_decoder_context *ctx = context; 308 CHECK_LENGTH(ctx, size); 309 cbor_item_t *res = cbor_new_definite_array(size); 310 CHECK_RES(ctx, res); 311 if (size > 0) { 312 PUSH_CTX_STACK(ctx, res, size); 313 } else { 314 _cbor_builder_append(res, ctx); 315 } 316 } 317 318 void cbor_builder_indef_array_start_callback(void *context) { 319 struct _cbor_decoder_context *ctx = context; 320 cbor_item_t *res = cbor_new_indefinite_array(); 321 CHECK_RES(ctx, res); 322 PUSH_CTX_STACK(ctx, res, 0); 323 } 324 325 void cbor_builder_indef_map_start_callback(void *context) { 326 struct _cbor_decoder_context *ctx = context; 327 cbor_item_t *res = cbor_new_indefinite_map(); 328 CHECK_RES(ctx, res); 329 PUSH_CTX_STACK(ctx, res, 0); 330 } 331 332 void cbor_builder_map_start_callback(void *context, uint64_t size) { 333 struct _cbor_decoder_context *ctx = context; 334 CHECK_LENGTH(ctx, size); 335 cbor_item_t *res = cbor_new_definite_map(size); 336 CHECK_RES(ctx, res); 337 if (size > 0) { 338 PUSH_CTX_STACK(ctx, res, size * 2); 339 } else { 340 _cbor_builder_append(res, ctx); 341 } 342 } 343 344 /** 345 * Is the (partially constructed) item indefinite? 346 */ 347 bool _cbor_is_indefinite(cbor_item_t *item) { 348 switch (item->type) { 349 case CBOR_TYPE_BYTESTRING: 350 return cbor_bytestring_is_indefinite(item); 351 case CBOR_TYPE_STRING: 352 return cbor_string_is_indefinite(item); 353 case CBOR_TYPE_ARRAY: 354 return cbor_array_is_indefinite(item); 355 case CBOR_TYPE_MAP: 356 return cbor_map_is_indefinite(item); 357 default: 358 return false; 359 } 360 } 361 362 void cbor_builder_indef_break_callback(void *context) { 363 struct _cbor_decoder_context *ctx = context; 364 /* There must be an item to break out of*/ 365 if (ctx->stack->size > 0) { 366 cbor_item_t *item = ctx->stack->top->item; 367 if (_cbor_is_indefinite( 368 item) && /* Only indefinite items can be terminated by 0xFF */ 369 /* Special case: we cannot append up if an indefinite map is incomplete 370 (we are expecting a value). */ 371 (item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) { 372 _cbor_stack_pop(ctx->stack); 373 _cbor_builder_append(item, ctx); 374 return; 375 } 376 } 377 378 ctx->syntax_error = true; 379 } 380 381 void cbor_builder_float2_callback(void *context, float value) { 382 struct _cbor_decoder_context *ctx = context; 383 cbor_item_t *res = cbor_new_float2(); 384 CHECK_RES(ctx, res); 385 cbor_set_float2(res, value); 386 _cbor_builder_append(res, ctx); 387 } 388 389 void cbor_builder_float4_callback(void *context, float value) { 390 struct _cbor_decoder_context *ctx = context; 391 cbor_item_t *res = cbor_new_float4(); 392 CHECK_RES(ctx, res); 393 cbor_set_float4(res, value); 394 _cbor_builder_append(res, ctx); 395 } 396 397 void cbor_builder_float8_callback(void *context, double value) { 398 struct _cbor_decoder_context *ctx = context; 399 cbor_item_t *res = cbor_new_float8(); 400 CHECK_RES(ctx, res); 401 cbor_set_float8(res, value); 402 _cbor_builder_append(res, ctx); 403 } 404 405 void cbor_builder_null_callback(void *context) { 406 struct _cbor_decoder_context *ctx = context; 407 cbor_item_t *res = cbor_new_null(); 408 CHECK_RES(ctx, res); 409 _cbor_builder_append(res, ctx); 410 } 411 412 void cbor_builder_undefined_callback(void *context) { 413 struct _cbor_decoder_context *ctx = context; 414 cbor_item_t *res = cbor_new_undef(); 415 CHECK_RES(ctx, res); 416 _cbor_builder_append(res, ctx); 417 } 418 419 void cbor_builder_boolean_callback(void *context, bool value) { 420 struct _cbor_decoder_context *ctx = context; 421 cbor_item_t *res = cbor_build_bool(value); 422 CHECK_RES(ctx, res); 423 _cbor_builder_append(res, ctx); 424 } 425 426 void cbor_builder_tag_callback(void *context, uint64_t value) { 427 struct _cbor_decoder_context *ctx = context; 428 cbor_item_t *res = cbor_new_tag(value); 429 CHECK_RES(ctx, res); 430 PUSH_CTX_STACK(ctx, res, 1); 431 } 432