1 /* 2 * Copyright (c) 2014-2019 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 // TODO: refactor this to take the parameter name, this is way too magical 91 #define CHECK_RES \ 92 do { \ 93 if (res == NULL) { \ 94 ctx->creation_failed = true; \ 95 return; \ 96 } \ 97 } while (0) 98 99 void cbor_builder_uint8_callback(void *context, uint8_t value) { 100 struct _cbor_decoder_context *ctx = context; 101 cbor_item_t *res = cbor_new_int8(); 102 CHECK_RES; 103 cbor_mark_uint(res); 104 cbor_set_uint8(res, value); 105 _cbor_builder_append(res, ctx); 106 } 107 108 void cbor_builder_uint16_callback(void *context, uint16_t value) { 109 struct _cbor_decoder_context *ctx = context; 110 cbor_item_t *res = cbor_new_int16(); 111 CHECK_RES; 112 cbor_mark_uint(res); 113 cbor_set_uint16(res, value); 114 _cbor_builder_append(res, ctx); 115 } 116 117 void cbor_builder_uint32_callback(void *context, uint32_t value) { 118 struct _cbor_decoder_context *ctx = context; 119 cbor_item_t *res = cbor_new_int32(); 120 CHECK_RES; 121 cbor_mark_uint(res); 122 cbor_set_uint32(res, value); 123 _cbor_builder_append(res, ctx); 124 } 125 126 void cbor_builder_uint64_callback(void *context, uint64_t value) { 127 struct _cbor_decoder_context *ctx = context; 128 cbor_item_t *res = cbor_new_int64(); 129 CHECK_RES; 130 cbor_mark_uint(res); 131 cbor_set_uint64(res, value); 132 _cbor_builder_append(res, ctx); 133 } 134 135 void cbor_builder_negint8_callback(void *context, uint8_t value) { 136 struct _cbor_decoder_context *ctx = context; 137 cbor_item_t *res = cbor_new_int8(); 138 CHECK_RES; 139 cbor_mark_negint(res); 140 cbor_set_uint8(res, value); 141 _cbor_builder_append(res, ctx); 142 } 143 144 void cbor_builder_negint16_callback(void *context, uint16_t value) { 145 struct _cbor_decoder_context *ctx = context; 146 cbor_item_t *res = cbor_new_int16(); 147 cbor_mark_negint(res); 148 cbor_set_uint16(res, value); 149 _cbor_builder_append(res, ctx); 150 } 151 152 void cbor_builder_negint32_callback(void *context, uint32_t value) { 153 struct _cbor_decoder_context *ctx = context; 154 cbor_item_t *res = cbor_new_int32(); 155 CHECK_RES; 156 cbor_mark_negint(res); 157 cbor_set_uint32(res, value); 158 _cbor_builder_append(res, ctx); 159 } 160 161 void cbor_builder_negint64_callback(void *context, uint64_t value) { 162 struct _cbor_decoder_context *ctx = context; 163 cbor_item_t *res = cbor_new_int64(); 164 CHECK_RES; 165 cbor_mark_negint(res); 166 cbor_set_uint64(res, value); 167 _cbor_builder_append(res, ctx); 168 } 169 170 void cbor_builder_byte_string_callback(void *context, cbor_data data, 171 size_t length) { 172 struct _cbor_decoder_context *ctx = context; 173 unsigned char *new_handle = _CBOR_MALLOC(length); 174 if (new_handle == NULL) { 175 ctx->creation_failed = true; 176 return; 177 } 178 179 memcpy(new_handle, data, length); 180 cbor_item_t *res = cbor_new_definite_bytestring(); 181 182 if (res == NULL) { 183 _CBOR_FREE(new_handle); 184 ctx->creation_failed = true; 185 return; 186 } 187 188 cbor_bytestring_set_handle(res, new_handle, length); 189 190 if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item)) { 191 if (cbor_bytestring_is_indefinite(ctx->stack->top->item)) { 192 cbor_bytestring_add_chunk(ctx->stack->top->item, cbor_move(res)); 193 } else { 194 cbor_decref(&res); 195 ctx->syntax_error = true; 196 } 197 } else { 198 _cbor_builder_append(res, ctx); 199 } 200 } 201 202 void cbor_builder_byte_string_start_callback(void *context) { 203 struct _cbor_decoder_context *ctx = context; 204 cbor_item_t *res = cbor_new_indefinite_bytestring(); 205 CHECK_RES; 206 _cbor_stack_push(ctx->stack, res, 0); 207 } 208 209 void cbor_builder_string_callback(void *context, cbor_data data, 210 size_t length) { 211 struct _cbor_decoder_context *ctx = context; 212 struct _cbor_unicode_status unicode_status; 213 214 size_t codepoint_count = 215 _cbor_unicode_codepoint_count(data, length, &unicode_status); 216 217 if (unicode_status.status == _CBOR_UNICODE_BADCP) { 218 ctx->syntax_error = true; 219 return; 220 } 221 222 unsigned char *new_handle = _CBOR_MALLOC(length); 223 224 if (new_handle == NULL) { 225 ctx->creation_failed = true; 226 return; 227 } 228 229 memcpy(new_handle, data, length); 230 cbor_item_t *res = cbor_new_definite_string(); 231 cbor_string_set_handle(res, new_handle, length); 232 res->metadata.string_metadata.codepoint_count = codepoint_count; 233 234 /* Careful here: order matters */ 235 if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item)) { 236 if (cbor_string_is_indefinite(ctx->stack->top->item)) { 237 cbor_string_add_chunk(ctx->stack->top->item, cbor_move(res)); 238 } else { 239 cbor_decref(&res); 240 ctx->syntax_error = true; 241 } 242 } else { 243 _cbor_builder_append(res, ctx); 244 } 245 } 246 247 void cbor_builder_string_start_callback(void *context) { 248 struct _cbor_decoder_context *ctx = context; 249 cbor_item_t *res = cbor_new_indefinite_string(); 250 CHECK_RES; 251 _cbor_stack_push(ctx->stack, res, 0); 252 } 253 254 void cbor_builder_array_start_callback(void *context, size_t size) { 255 struct _cbor_decoder_context *ctx = context; 256 cbor_item_t *res = cbor_new_definite_array(size); 257 CHECK_RES; 258 if (size > 0) { 259 _cbor_stack_push(ctx->stack, res, size); 260 } else { 261 _cbor_builder_append(res, ctx); 262 } 263 } 264 265 void cbor_builder_indef_array_start_callback(void *context) { 266 struct _cbor_decoder_context *ctx = context; 267 cbor_item_t *res = cbor_new_indefinite_array(); 268 CHECK_RES; 269 _cbor_stack_push(ctx->stack, res, 0); 270 } 271 272 void cbor_builder_indef_map_start_callback(void *context) { 273 struct _cbor_decoder_context *ctx = context; 274 cbor_item_t *res = cbor_new_indefinite_map(); 275 CHECK_RES; 276 _cbor_stack_push(ctx->stack, res, 0); 277 } 278 279 void cbor_builder_map_start_callback(void *context, size_t size) { 280 struct _cbor_decoder_context *ctx = context; 281 cbor_item_t *res = cbor_new_definite_map(size); 282 CHECK_RES; 283 if (size > 0) { 284 _cbor_stack_push(ctx->stack, res, size * 2); 285 } else { 286 _cbor_builder_append(res, ctx); 287 } 288 } 289 290 /** 291 * Is the (partially constructed) item indefinite? 292 */ 293 bool _cbor_is_indefinite(cbor_item_t *item) { 294 switch (item->type) { 295 case CBOR_TYPE_BYTESTRING: 296 return item->metadata.bytestring_metadata.type == 297 _CBOR_METADATA_INDEFINITE; 298 case CBOR_TYPE_STRING: 299 return item->metadata.string_metadata.type == _CBOR_METADATA_INDEFINITE; 300 case CBOR_TYPE_ARRAY: 301 return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE; 302 case CBOR_TYPE_MAP: 303 return item->metadata.map_metadata.type == _CBOR_METADATA_INDEFINITE; 304 default: 305 return false; 306 } 307 } 308 309 void cbor_builder_indef_break_callback(void *context) { 310 struct _cbor_decoder_context *ctx = context; 311 /* There must be an item to break out of*/ 312 if (ctx->stack->size > 0) { 313 cbor_item_t *item = ctx->stack->top->item; 314 if (_cbor_is_indefinite( 315 item) && /* Only indefinite items can be terminated by 0xFF */ 316 /* Special case: we cannot append up if an indefinite map is incomplete 317 (we are expecting a value). */ 318 (item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) { 319 _cbor_stack_pop(ctx->stack); 320 _cbor_builder_append(item, ctx); 321 return; 322 } 323 } 324 325 ctx->syntax_error = true; 326 } 327 328 void cbor_builder_float2_callback(void *context, float value) { 329 struct _cbor_decoder_context *ctx = context; 330 cbor_item_t *res = cbor_new_float2(); 331 cbor_set_float2(res, value); 332 _cbor_builder_append(res, ctx); 333 } 334 335 void cbor_builder_float4_callback(void *context, float value) { 336 struct _cbor_decoder_context *ctx = context; 337 cbor_item_t *res = cbor_new_float4(); 338 CHECK_RES; 339 cbor_set_float4(res, value); 340 _cbor_builder_append(res, ctx); 341 } 342 343 void cbor_builder_float8_callback(void *context, double value) { 344 struct _cbor_decoder_context *ctx = context; 345 cbor_item_t *res = cbor_new_float8(); 346 CHECK_RES; 347 cbor_set_float8(res, value); 348 _cbor_builder_append(res, ctx); 349 } 350 351 void cbor_builder_null_callback(void *context) { 352 struct _cbor_decoder_context *ctx = context; 353 cbor_item_t *res = cbor_new_null(); 354 CHECK_RES; 355 _cbor_builder_append(res, ctx); 356 } 357 358 void cbor_builder_undefined_callback(void *context) { 359 struct _cbor_decoder_context *ctx = context; 360 cbor_item_t *res = cbor_new_undef(); 361 CHECK_RES; 362 _cbor_builder_append(res, ctx); 363 } 364 365 void cbor_builder_boolean_callback(void *context, bool value) { 366 struct _cbor_decoder_context *ctx = context; 367 cbor_item_t *res = cbor_build_bool(value); 368 CHECK_RES; 369 _cbor_builder_append(res, ctx); 370 } 371 372 void cbor_builder_tag_callback(void *context, uint64_t value) { 373 struct _cbor_decoder_context *ctx = context; 374 cbor_item_t *res = cbor_new_tag(value); 375 CHECK_RES; 376 _cbor_stack_push(ctx->stack, res, 1); 377 } 378