Path: blob/main/contrib/libcbor/src/cbor/internal/builder_callbacks.c
39566 views
/*1* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>2*3* libcbor is free software; you can redistribute it and/or modify4* it under the terms of the MIT license. See LICENSE for details.5*/67#include "builder_callbacks.h"89#include <string.h>1011#include "../arrays.h"12#include "../bytestrings.h"13#include "../common.h"14#include "../floats_ctrls.h"15#include "../ints.h"16#include "../maps.h"17#include "../strings.h"18#include "../tags.h"19#include "unicode.h"2021// `_cbor_builder_append` takes ownership of `item`. If adding the item to22// parent container fails, `item` will be deallocated to prevent memory.23void _cbor_builder_append(cbor_item_t *item,24struct _cbor_decoder_context *ctx) {25if (ctx->stack->size == 0) {26/* Top level item */27ctx->root = item;28return;29}30/* Part of a bigger structure */31switch (ctx->stack->top->item->type) {32// Handle Arrays and Maps since they can contain subitems of any type.33// Byte/string construction from chunks is handled in the respective chunk34// handlers.35case CBOR_TYPE_ARRAY: {36if (cbor_array_is_definite(ctx->stack->top->item)) {37// We don't need an explicit check for whether the item still belongs38// into this array because if there are extra items, they will cause a39// syntax error when decoded.40CBOR_ASSERT(ctx->stack->top->subitems > 0);41// This should never happen since the definite array should be42// preallocated for the expected number of items.43if (!cbor_array_push(ctx->stack->top->item, item)) {44ctx->creation_failed = true;45cbor_decref(&item);46break;47}48cbor_decref(&item);49ctx->stack->top->subitems--;50if (ctx->stack->top->subitems == 0) {51cbor_item_t *stack_item = ctx->stack->top->item;52_cbor_stack_pop(ctx->stack);53_cbor_builder_append(stack_item, ctx);54}55} else {56/* Indefinite array, don't bother with subitems */57if (!cbor_array_push(ctx->stack->top->item, item)) {58ctx->creation_failed = true;59}60cbor_decref(&item);61}62break;63}64case CBOR_TYPE_MAP: {65// Handle both definite and indefinite maps the same initially.66// Note: We use 0 and 1 subitems to distinguish between keys and values in67// indefinite items68if (ctx->stack->top->subitems % 2) {69// Odd record, this is a value.70ctx->creation_failed =71!_cbor_map_add_value(ctx->stack->top->item, item);72// Adding a value never fails since the memory is allocated when the73// key is added74CBOR_ASSERT(!ctx->creation_failed);75} else {76// Even record, this is a key.77if (!_cbor_map_add_key(ctx->stack->top->item, item)) {78ctx->creation_failed = true;79cbor_decref(&item);80break;81}82}83cbor_decref(&item);84if (cbor_map_is_definite(ctx->stack->top->item)) {85CBOR_ASSERT(ctx->stack->top->subitems > 0);86ctx->stack->top->subitems--;87if (ctx->stack->top->subitems == 0) {88cbor_item_t *map_entry = ctx->stack->top->item;89_cbor_stack_pop(ctx->stack);90_cbor_builder_append(map_entry, ctx);91}92} else {93ctx->stack->top->subitems ^=941; /* Flip the indicator for indefinite items */95}96break;97}98case CBOR_TYPE_TAG: {99CBOR_ASSERT(ctx->stack->top->subitems == 1);100cbor_tag_set_item(ctx->stack->top->item, item);101cbor_decref(&item); /* Give up on our reference */102cbor_item_t *tagged_item = ctx->stack->top->item;103_cbor_stack_pop(ctx->stack);104_cbor_builder_append(tagged_item, ctx);105break;106}107// We have an item to append but nothing to append it to.108default: {109cbor_decref(&item);110ctx->syntax_error = true;111}112}113}114115#define CHECK_RES(ctx, res) \116do { \117if (res == NULL) { \118ctx->creation_failed = true; \119return; \120} \121} while (0)122123// Check that the length fits into size_t. If not, we cannot possibly allocate124// the required memory and should fail fast.125#define CHECK_LENGTH(ctx, length) \126do { \127if (length > SIZE_MAX) { \128ctx->creation_failed = true; \129return; \130} \131} while (0)132133#define PUSH_CTX_STACK(ctx, res, subitems) \134do { \135if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \136cbor_decref(&res); \137ctx->creation_failed = true; \138} \139} while (0)140141void cbor_builder_uint8_callback(void *context, uint8_t value) {142struct _cbor_decoder_context *ctx = context;143cbor_item_t *res = cbor_new_int8();144CHECK_RES(ctx, res);145cbor_mark_uint(res);146cbor_set_uint8(res, value);147_cbor_builder_append(res, ctx);148}149150void cbor_builder_uint16_callback(void *context, uint16_t value) {151struct _cbor_decoder_context *ctx = context;152cbor_item_t *res = cbor_new_int16();153CHECK_RES(ctx, res);154cbor_mark_uint(res);155cbor_set_uint16(res, value);156_cbor_builder_append(res, ctx);157}158159void cbor_builder_uint32_callback(void *context, uint32_t value) {160struct _cbor_decoder_context *ctx = context;161cbor_item_t *res = cbor_new_int32();162CHECK_RES(ctx, res);163cbor_mark_uint(res);164cbor_set_uint32(res, value);165_cbor_builder_append(res, ctx);166}167168void cbor_builder_uint64_callback(void *context, uint64_t value) {169struct _cbor_decoder_context *ctx = context;170cbor_item_t *res = cbor_new_int64();171CHECK_RES(ctx, res);172cbor_mark_uint(res);173cbor_set_uint64(res, value);174_cbor_builder_append(res, ctx);175}176177void cbor_builder_negint8_callback(void *context, uint8_t value) {178struct _cbor_decoder_context *ctx = context;179cbor_item_t *res = cbor_new_int8();180CHECK_RES(ctx, res);181cbor_mark_negint(res);182cbor_set_uint8(res, value);183_cbor_builder_append(res, ctx);184}185186void cbor_builder_negint16_callback(void *context, uint16_t value) {187struct _cbor_decoder_context *ctx = context;188cbor_item_t *res = cbor_new_int16();189CHECK_RES(ctx, res);190cbor_mark_negint(res);191cbor_set_uint16(res, value);192_cbor_builder_append(res, ctx);193}194195void cbor_builder_negint32_callback(void *context, uint32_t value) {196struct _cbor_decoder_context *ctx = context;197cbor_item_t *res = cbor_new_int32();198CHECK_RES(ctx, res);199cbor_mark_negint(res);200cbor_set_uint32(res, value);201_cbor_builder_append(res, ctx);202}203204void cbor_builder_negint64_callback(void *context, uint64_t value) {205struct _cbor_decoder_context *ctx = context;206cbor_item_t *res = cbor_new_int64();207CHECK_RES(ctx, res);208cbor_mark_negint(res);209cbor_set_uint64(res, value);210_cbor_builder_append(res, ctx);211}212213void cbor_builder_byte_string_callback(void *context, cbor_data data,214uint64_t length) {215struct _cbor_decoder_context *ctx = context;216CHECK_LENGTH(ctx, length);217unsigned char *new_handle = _cbor_malloc(length);218if (new_handle == NULL) {219ctx->creation_failed = true;220return;221}222223memcpy(new_handle, data, length);224cbor_item_t *new_chunk = cbor_new_definite_bytestring();225226if (new_chunk == NULL) {227_cbor_free(new_handle);228ctx->creation_failed = true;229return;230}231232cbor_bytestring_set_handle(new_chunk, new_handle, length);233234// If an indef bytestring is on the stack, extend it (if it were closed, it235// would have been popped). Handle any syntax errors upstream.236if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item) &&237cbor_bytestring_is_indefinite(ctx->stack->top->item)) {238if (!cbor_bytestring_add_chunk(ctx->stack->top->item, new_chunk)) {239ctx->creation_failed = true;240}241cbor_decref(&new_chunk);242} else {243_cbor_builder_append(new_chunk, ctx);244}245}246247void cbor_builder_byte_string_start_callback(void *context) {248struct _cbor_decoder_context *ctx = context;249cbor_item_t *res = cbor_new_indefinite_bytestring();250CHECK_RES(ctx, res);251PUSH_CTX_STACK(ctx, res, 0);252}253254void cbor_builder_string_callback(void *context, cbor_data data,255uint64_t length) {256struct _cbor_decoder_context *ctx = context;257CHECK_LENGTH(ctx, length);258259unsigned char *new_handle = _cbor_malloc(length);260if (new_handle == NULL) {261ctx->creation_failed = true;262return;263}264265memcpy(new_handle, data, length);266cbor_item_t *new_chunk = cbor_new_definite_string();267if (new_chunk == NULL) {268_cbor_free(new_handle);269ctx->creation_failed = true;270return;271}272cbor_string_set_handle(new_chunk, new_handle, length);273274// If an indef string is on the stack, extend it (if it were closed, it would275// have been popped). Handle any syntax errors upstream.276if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) &&277cbor_string_is_indefinite(ctx->stack->top->item)) {278if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) {279ctx->creation_failed = true;280}281cbor_decref(&new_chunk);282} else {283_cbor_builder_append(new_chunk, ctx);284}285}286287void cbor_builder_string_start_callback(void *context) {288struct _cbor_decoder_context *ctx = context;289cbor_item_t *res = cbor_new_indefinite_string();290CHECK_RES(ctx, res);291PUSH_CTX_STACK(ctx, res, 0);292}293294void cbor_builder_array_start_callback(void *context, uint64_t size) {295struct _cbor_decoder_context *ctx = context;296CHECK_LENGTH(ctx, size);297cbor_item_t *res = cbor_new_definite_array(size);298CHECK_RES(ctx, res);299if (size > 0) {300PUSH_CTX_STACK(ctx, res, size);301} else {302_cbor_builder_append(res, ctx);303}304}305306void cbor_builder_indef_array_start_callback(void *context) {307struct _cbor_decoder_context *ctx = context;308cbor_item_t *res = cbor_new_indefinite_array();309CHECK_RES(ctx, res);310PUSH_CTX_STACK(ctx, res, 0);311}312313void cbor_builder_indef_map_start_callback(void *context) {314struct _cbor_decoder_context *ctx = context;315cbor_item_t *res = cbor_new_indefinite_map();316CHECK_RES(ctx, res);317PUSH_CTX_STACK(ctx, res, 0);318}319320void cbor_builder_map_start_callback(void *context, uint64_t size) {321struct _cbor_decoder_context *ctx = context;322CHECK_LENGTH(ctx, size);323cbor_item_t *res = cbor_new_definite_map(size);324CHECK_RES(ctx, res);325if (size > 0) {326PUSH_CTX_STACK(ctx, res, size * 2);327} else {328_cbor_builder_append(res, ctx);329}330}331332/**333* Is the (partially constructed) item indefinite?334*/335bool _cbor_is_indefinite(cbor_item_t *item) {336switch (item->type) {337case CBOR_TYPE_BYTESTRING:338return cbor_bytestring_is_indefinite(item);339case CBOR_TYPE_STRING:340return cbor_string_is_indefinite(item);341case CBOR_TYPE_ARRAY:342return cbor_array_is_indefinite(item);343case CBOR_TYPE_MAP:344return cbor_map_is_indefinite(item);345default:346// Should never happen since a non-nested item cannot be on top of the347// stack.348return false;349}350}351352void cbor_builder_indef_break_callback(void *context) {353struct _cbor_decoder_context *ctx = context;354/* There must be an item to break out of*/355if (ctx->stack->size > 0) {356cbor_item_t *item = ctx->stack->top->item;357if (_cbor_is_indefinite(358item) && /* Only indefinite items can be terminated by 0xFF */359/* Special case: we cannot append up if an indefinite map is incomplete360(we are expecting a value). */361(item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) {362_cbor_stack_pop(ctx->stack);363_cbor_builder_append(item, ctx);364return;365}366}367368ctx->syntax_error = true;369}370371void cbor_builder_float2_callback(void *context, float value) {372struct _cbor_decoder_context *ctx = context;373cbor_item_t *res = cbor_new_float2();374CHECK_RES(ctx, res);375cbor_set_float2(res, value);376_cbor_builder_append(res, ctx);377}378379void cbor_builder_float4_callback(void *context, float value) {380struct _cbor_decoder_context *ctx = context;381cbor_item_t *res = cbor_new_float4();382CHECK_RES(ctx, res);383cbor_set_float4(res, value);384_cbor_builder_append(res, ctx);385}386387void cbor_builder_float8_callback(void *context, double value) {388struct _cbor_decoder_context *ctx = context;389cbor_item_t *res = cbor_new_float8();390CHECK_RES(ctx, res);391cbor_set_float8(res, value);392_cbor_builder_append(res, ctx);393}394395void cbor_builder_null_callback(void *context) {396struct _cbor_decoder_context *ctx = context;397cbor_item_t *res = cbor_new_null();398CHECK_RES(ctx, res);399_cbor_builder_append(res, ctx);400}401402void cbor_builder_undefined_callback(void *context) {403struct _cbor_decoder_context *ctx = context;404cbor_item_t *res = cbor_new_undef();405CHECK_RES(ctx, res);406_cbor_builder_append(res, ctx);407}408409void cbor_builder_boolean_callback(void *context, bool value) {410struct _cbor_decoder_context *ctx = context;411cbor_item_t *res = cbor_build_bool(value);412CHECK_RES(ctx, res);413_cbor_builder_append(res, ctx);414}415416void cbor_builder_tag_callback(void *context, uint64_t value) {417struct _cbor_decoder_context *ctx = context;418cbor_item_t *res = cbor_new_tag(value);419CHECK_RES(ctx, res);420PUSH_CTX_STACK(ctx, res, 1);421}422423424