#include "builder_callbacks.h"
#include <string.h>
#include "../arrays.h"
#include "../bytestrings.h"
#include "../common.h"
#include "../floats_ctrls.h"
#include "../ints.h"
#include "../maps.h"
#include "../strings.h"
#include "../tags.h"
#include "unicode.h"
void _cbor_builder_append(cbor_item_t *item,
struct _cbor_decoder_context *ctx) {
if (ctx->stack->size == 0) {
ctx->root = item;
return;
}
switch (ctx->stack->top->item->type) {
case CBOR_TYPE_ARRAY: {
if (cbor_array_is_definite(ctx->stack->top->item)) {
CBOR_ASSERT(ctx->stack->top->subitems > 0);
if (!cbor_array_push(ctx->stack->top->item, item)) {
ctx->creation_failed = true;
cbor_decref(&item);
break;
}
cbor_decref(&item);
ctx->stack->top->subitems--;
if (ctx->stack->top->subitems == 0) {
cbor_item_t *stack_item = ctx->stack->top->item;
_cbor_stack_pop(ctx->stack);
_cbor_builder_append(stack_item, ctx);
}
} else {
if (!cbor_array_push(ctx->stack->top->item, item)) {
ctx->creation_failed = true;
}
cbor_decref(&item);
}
break;
}
case CBOR_TYPE_MAP: {
if (ctx->stack->top->subitems % 2) {
if (!_cbor_map_add_value(ctx->stack->top->item, item)) {
ctx->creation_failed = true;
cbor_decref(&item);
break;
}
} else {
if (!_cbor_map_add_key(ctx->stack->top->item, item)) {
ctx->creation_failed = true;
cbor_decref(&item);
break;
}
}
cbor_decref(&item);
if (cbor_map_is_definite(ctx->stack->top->item)) {
CBOR_ASSERT(ctx->stack->top->subitems > 0);
ctx->stack->top->subitems--;
if (ctx->stack->top->subitems == 0) {
cbor_item_t *map_entry = ctx->stack->top->item;
_cbor_stack_pop(ctx->stack);
_cbor_builder_append(map_entry, ctx);
}
} else {
ctx->stack->top->subitems ^=
1;
}
break;
}
case CBOR_TYPE_TAG: {
CBOR_ASSERT(ctx->stack->top->subitems == 1);
cbor_tag_set_item(ctx->stack->top->item, item);
cbor_decref(&item);
cbor_item_t *tagged_item = ctx->stack->top->item;
_cbor_stack_pop(ctx->stack);
_cbor_builder_append(tagged_item, ctx);
break;
}
default: {
cbor_decref(&item);
ctx->syntax_error = true;
}
}
}
#define CHECK_RES(ctx, res) \
do { \
if (res == NULL) { \
ctx->creation_failed = true; \
return; \
} \
} while (0)
#define CHECK_LENGTH(ctx, length) \
do { \
if (length > SIZE_MAX) { \
ctx->creation_failed = true; \
return; \
} \
} while (0)
#define PUSH_CTX_STACK(ctx, res, subitems) \
do { \
if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \
cbor_decref(&res); \
ctx->creation_failed = true; \
} \
} while (0)
void cbor_builder_uint8_callback(void *context, uint8_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int8();
CHECK_RES(ctx, res);
cbor_mark_uint(res);
cbor_set_uint8(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_uint16_callback(void *context, uint16_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int16();
CHECK_RES(ctx, res);
cbor_mark_uint(res);
cbor_set_uint16(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_uint32_callback(void *context, uint32_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int32();
CHECK_RES(ctx, res);
cbor_mark_uint(res);
cbor_set_uint32(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_uint64_callback(void *context, uint64_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int64();
CHECK_RES(ctx, res);
cbor_mark_uint(res);
cbor_set_uint64(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_negint8_callback(void *context, uint8_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int8();
CHECK_RES(ctx, res);
cbor_mark_negint(res);
cbor_set_uint8(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_negint16_callback(void *context, uint16_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int16();
CHECK_RES(ctx, res);
cbor_mark_negint(res);
cbor_set_uint16(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_negint32_callback(void *context, uint32_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int32();
CHECK_RES(ctx, res);
cbor_mark_negint(res);
cbor_set_uint32(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_negint64_callback(void *context, uint64_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int64();
CHECK_RES(ctx, res);
cbor_mark_negint(res);
cbor_set_uint64(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_byte_string_callback(void *context, cbor_data data,
uint64_t length) {
struct _cbor_decoder_context *ctx = context;
CHECK_LENGTH(ctx, length);
unsigned char *new_handle = _cbor_malloc(length);
if (new_handle == NULL) {
ctx->creation_failed = true;
return;
}
memcpy(new_handle, data, length);
cbor_item_t *new_chunk = cbor_new_definite_bytestring();
if (new_chunk == NULL) {
_cbor_free(new_handle);
ctx->creation_failed = true;
return;
}
cbor_bytestring_set_handle(new_chunk, new_handle, length);
if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item) &&
cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
if (!cbor_bytestring_add_chunk(ctx->stack->top->item, new_chunk)) {
ctx->creation_failed = true;
}
cbor_decref(&new_chunk);
} else {
_cbor_builder_append(new_chunk, ctx);
}
}
void cbor_builder_byte_string_start_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_indefinite_bytestring();
CHECK_RES(ctx, res);
PUSH_CTX_STACK(ctx, res, 0);
}
void cbor_builder_string_callback(void *context, cbor_data data,
uint64_t length) {
struct _cbor_decoder_context *ctx = context;
CHECK_LENGTH(ctx, length);
struct _cbor_unicode_status unicode_status;
uint64_t codepoint_count =
_cbor_unicode_codepoint_count(data, length, &unicode_status);
if (unicode_status.status != _CBOR_UNICODE_OK) {
ctx->syntax_error = true;
return;
}
CBOR_ASSERT(codepoint_count <= length);
unsigned char *new_handle = _cbor_malloc(length);
if (new_handle == NULL) {
ctx->creation_failed = true;
return;
}
memcpy(new_handle, data, length);
cbor_item_t *new_chunk = cbor_new_definite_string();
if (new_chunk == NULL) {
_cbor_free(new_handle);
ctx->creation_failed = true;
return;
}
cbor_string_set_handle(new_chunk, new_handle, length);
new_chunk->metadata.string_metadata.codepoint_count = codepoint_count;
if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) &&
cbor_string_is_indefinite(ctx->stack->top->item)) {
if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) {
ctx->creation_failed = true;
}
cbor_decref(&new_chunk);
} else {
_cbor_builder_append(new_chunk, ctx);
}
}
void cbor_builder_string_start_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_indefinite_string();
CHECK_RES(ctx, res);
PUSH_CTX_STACK(ctx, res, 0);
}
void cbor_builder_array_start_callback(void *context, uint64_t size) {
struct _cbor_decoder_context *ctx = context;
CHECK_LENGTH(ctx, size);
cbor_item_t *res = cbor_new_definite_array(size);
CHECK_RES(ctx, res);
if (size > 0) {
PUSH_CTX_STACK(ctx, res, size);
} else {
_cbor_builder_append(res, ctx);
}
}
void cbor_builder_indef_array_start_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_indefinite_array();
CHECK_RES(ctx, res);
PUSH_CTX_STACK(ctx, res, 0);
}
void cbor_builder_indef_map_start_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_indefinite_map();
CHECK_RES(ctx, res);
PUSH_CTX_STACK(ctx, res, 0);
}
void cbor_builder_map_start_callback(void *context, uint64_t size) {
struct _cbor_decoder_context *ctx = context;
CHECK_LENGTH(ctx, size);
cbor_item_t *res = cbor_new_definite_map(size);
CHECK_RES(ctx, res);
if (size > 0) {
PUSH_CTX_STACK(ctx, res, size * 2);
} else {
_cbor_builder_append(res, ctx);
}
}
bool _cbor_is_indefinite(cbor_item_t *item) {
switch (item->type) {
case CBOR_TYPE_BYTESTRING:
return cbor_bytestring_is_indefinite(item);
case CBOR_TYPE_STRING:
return cbor_string_is_indefinite(item);
case CBOR_TYPE_ARRAY:
return cbor_array_is_indefinite(item);
case CBOR_TYPE_MAP:
return cbor_map_is_indefinite(item);
default:
return false;
}
}
void cbor_builder_indef_break_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
if (ctx->stack->size > 0) {
cbor_item_t *item = ctx->stack->top->item;
if (_cbor_is_indefinite(
item) &&
(item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) {
_cbor_stack_pop(ctx->stack);
_cbor_builder_append(item, ctx);
return;
}
}
ctx->syntax_error = true;
}
void cbor_builder_float2_callback(void *context, float value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_float2();
CHECK_RES(ctx, res);
cbor_set_float2(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_float4_callback(void *context, float value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_float4();
CHECK_RES(ctx, res);
cbor_set_float4(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_float8_callback(void *context, double value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_float8();
CHECK_RES(ctx, res);
cbor_set_float8(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_null_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_null();
CHECK_RES(ctx, res);
_cbor_builder_append(res, ctx);
}
void cbor_builder_undefined_callback(void *context) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_undef();
CHECK_RES(ctx, res);
_cbor_builder_append(res, ctx);
}
void cbor_builder_boolean_callback(void *context, bool value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_build_bool(value);
CHECK_RES(ctx, res);
_cbor_builder_append(res, ctx);
}
void cbor_builder_tag_callback(void *context, uint64_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_tag(value);
CHECK_RES(ctx, res);
PUSH_CTX_STACK(ctx, res, 1);
}