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 19void _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 99void 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 108void 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 117void 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 126void 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 135void 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 144void 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 152void 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 161void 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 170void 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 202void 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 209void 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 247void 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 254void 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 265void 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 272void 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 279void 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 */ 293bool _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 309void 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 328void 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 335void 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 343void 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 351void 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 358void 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 365void 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 372void 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