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