diff options
author | 2019-11-14 21:11:34 +0000 | |
---|---|---|
committer | 2019-11-14 21:11:34 +0000 | |
commit | da0d961c2c28322a016c9e47e9898b8a67695a06 (patch) | |
tree | 98cc58b7052570a785fb26702de946f8f6519f3a /lib/libcbor/src | |
parent | Add missing cross-reference to NOTES section. (diff) | |
download | wireguard-openbsd-da0d961c2c28322a016c9e47e9898b8a67695a06.tar.xz wireguard-openbsd-da0d961c2c28322a016c9e47e9898b8a67695a06.zip |
Add libcbor; an implementation of the Concise Binary Object
Representation (CBOR) encoding format defined in RFC7049.
This is a dependency of libfido2, that we'll use for U2F/FIDO
support in OpenSSH.
feedback and "Looks good enough to me" deraadt@
Diffstat (limited to 'lib/libcbor/src')
42 files changed, 5810 insertions, 0 deletions
diff --git a/lib/libcbor/src/allocators.c b/lib/libcbor/src/allocators.c new file mode 100644 index 00000000000..ff22509a193 --- /dev/null +++ b/lib/libcbor/src/allocators.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "cbor/common.h" + +_cbor_malloc_t _cbor_malloc = malloc; +_cbor_realloc_t _cbor_realloc = realloc; +_cbor_free_t _cbor_free = free; + +void cbor_set_allocs(_cbor_malloc_t custom_malloc, _cbor_realloc_t custom_realloc, _cbor_free_t custom_free) +{ + _cbor_malloc = custom_malloc; + _cbor_realloc = custom_realloc; + _cbor_free = custom_free; +} diff --git a/lib/libcbor/src/cbor.c b/lib/libcbor/src/cbor.c new file mode 100644 index 00000000000..86a3012480c --- /dev/null +++ b/lib/libcbor/src/cbor.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "cbor.h" +#include "cbor/internal/builder_callbacks.h" +#include "cbor/internal/loaders.h" + +cbor_item_t * cbor_load(cbor_data source, + size_t source_size, + struct cbor_load_result *result) +{ + /* Context stack */ + static struct cbor_callbacks callbacks = { + .uint8 = &cbor_builder_uint8_callback, + .uint16 = &cbor_builder_uint16_callback, + .uint32 = &cbor_builder_uint32_callback, + .uint64 = &cbor_builder_uint64_callback, + + .negint8 = &cbor_builder_negint8_callback, + .negint16 = &cbor_builder_negint16_callback, + .negint32 = &cbor_builder_negint32_callback, + .negint64 = &cbor_builder_negint64_callback, + + .byte_string = &cbor_builder_byte_string_callback, + .byte_string_start = &cbor_builder_byte_string_start_callback, + + .string = &cbor_builder_string_callback, + .string_start = &cbor_builder_string_start_callback, + + .array_start = &cbor_builder_array_start_callback, + .indef_array_start = &cbor_builder_indef_array_start_callback, + + .map_start = &cbor_builder_map_start_callback, + .indef_map_start = &cbor_builder_indef_map_start_callback, + + .tag = &cbor_builder_tag_callback, + + .null = &cbor_builder_null_callback, + .undefined = &cbor_builder_undefined_callback, + .boolean = &cbor_builder_boolean_callback, + .float2 = &cbor_builder_float2_callback, + .float4 = &cbor_builder_float4_callback, + .float8 = &cbor_builder_float8_callback, + .indef_break = &cbor_builder_indef_break_callback + }; + + if (source_size == 0) { + result->error.code = CBOR_ERR_NODATA; + return NULL; + } + struct _cbor_stack stack = _cbor_stack_init(); + + /* Target for callbacks */ + struct _cbor_decoder_context context = (struct _cbor_decoder_context) { + .stack = &stack, + .creation_failed = false, + .syntax_error = false + }; + struct cbor_decoder_result decode_result; + *result = (struct cbor_load_result) {.read = 0, .error = {.code = CBOR_ERR_NONE}}; + + do { + if (source_size > result->read) { /* Check for overflows */ + decode_result = cbor_stream_decode( + source + result->read, + source_size - result->read, + &callbacks, + &context); + } else { + result->error = (struct cbor_error) { + .code = CBOR_ERR_NOTENOUGHDATA, + .position = result->read + }; + goto error; + } + + switch (decode_result.status) { + case CBOR_DECODER_FINISHED: + /* Everything OK */ + { + result->read += decode_result.read; + break; + } + case CBOR_DECODER_NEDATA: + /* Data length doesn't match MTB expectation */ + { + result->error.code = CBOR_ERR_NOTENOUGHDATA; + goto error; + } + case CBOR_DECODER_EBUFFER: + /* Fallthrough */ + case CBOR_DECODER_ERROR: + /* Reserved/malformated item */ + { + result->error.code = CBOR_ERR_MALFORMATED; + goto error; + } + } + + if (context.creation_failed) { + /* Most likely unsuccessful allocation - our callback has failed */ + result->error.code = CBOR_ERR_MEMERROR; + goto error; + } else if (context.syntax_error) { + result->error.code = CBOR_ERR_SYNTAXERROR; + goto error; + } + } while (stack.size > 0); + + /* Move the result before free */ + cbor_item_t *result_item = context.root; + return result_item; + + error: + result->error.position = result->read; + //debug_print("Failed with decoder error %d at %d\n", result->error.code, result->error.position); + //cbor_describe(stack.top->item, stdout); + /* Free the stack */ + while (stack.size > 0) { + cbor_decref(&stack.top->item); + _cbor_stack_pop(&stack); + } + return NULL; +} + + +static cbor_item_t * _cbor_copy_int(cbor_item_t * item, bool negative) +{ + cbor_item_t * res; + switch (cbor_int_get_width(item)) { + case CBOR_INT_8: res = cbor_build_uint8(cbor_get_uint8(item)); break; + case CBOR_INT_16: res = cbor_build_uint16(cbor_get_uint16(item)); break; + case CBOR_INT_32: res = cbor_build_uint32(cbor_get_uint32(item)); break; + case CBOR_INT_64: res = cbor_build_uint64(cbor_get_uint64(item)); break; + default: return NULL; + } + + if (negative) + cbor_mark_negint(res); + + return res; +} + +static cbor_item_t * _cbor_copy_float_ctrl(cbor_item_t * item) +{ + switch (cbor_float_get_width(item)) { + case CBOR_FLOAT_0: + return cbor_build_ctrl(cbor_ctrl_value(item)); + case CBOR_FLOAT_16: + return cbor_build_float2(cbor_float_get_float2(item)); + case CBOR_FLOAT_32: + return cbor_build_float4(cbor_float_get_float4(item)); + case CBOR_FLOAT_64: + return cbor_build_float8(cbor_float_get_float8(item)); + } + + return NULL; +} + +cbor_item_t * cbor_copy(cbor_item_t * item) +{ + switch (cbor_typeof(item)) { + case CBOR_TYPE_UINT: + return _cbor_copy_int(item, false); + case CBOR_TYPE_NEGINT: + return _cbor_copy_int(item, true); + case CBOR_TYPE_BYTESTRING: + if (cbor_bytestring_is_definite(item)) { + return cbor_build_bytestring(cbor_bytestring_handle(item), cbor_bytestring_length(item)); + } else { + cbor_item_t * res = cbor_new_indefinite_bytestring(); + for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) + cbor_bytestring_add_chunk( + res, + cbor_move( + cbor_copy(cbor_bytestring_chunks_handle(item)[i]) + ) + ); + return res; + } + case CBOR_TYPE_STRING: + if (cbor_string_is_definite(item)) { + return cbor_build_stringn((const char *) cbor_string_handle(item), cbor_string_length(item)); + } else { + cbor_item_t * res = cbor_new_indefinite_string(); + for (size_t i = 0; i < cbor_string_chunk_count(item); i++) + cbor_string_add_chunk( + res, + cbor_move( + cbor_copy(cbor_string_chunks_handle(item)[i]) + ) + ); + return res; + } + case CBOR_TYPE_ARRAY: { + cbor_item_t * res; + if (cbor_array_is_definite(item)) + res = cbor_new_definite_array(cbor_array_size(item)); + else + res = cbor_new_indefinite_array(); + + for (size_t i = 0; i < cbor_array_size(item); i++) + cbor_array_push( + res, + cbor_move(cbor_copy(cbor_move(cbor_array_get(item, i)))) + ); + return res; + } + case CBOR_TYPE_MAP: { + cbor_item_t * res; + if (cbor_map_is_definite(item)) + res = cbor_new_definite_map(cbor_map_size(item)); + else + res = cbor_new_indefinite_map(); + + struct cbor_pair * it = cbor_map_handle(item); + for (size_t i = 0; i < cbor_map_size(item); i++) + cbor_map_add(res, (struct cbor_pair) { + .key = cbor_move(cbor_copy(it[i].key)), + .value = cbor_move(cbor_copy(it[i].value)) + }); + return res; + } + case CBOR_TYPE_TAG: + return cbor_build_tag( + cbor_tag_value(item), + cbor_move(cbor_copy(cbor_tag_item(item))) + ); + case CBOR_TYPE_FLOAT_CTRL: + return _cbor_copy_float_ctrl(item); + } + + return NULL; +} + +#if CBOR_PRETTY_PRINTER + +#include <inttypes.h> +#include <wchar.h> +#include <locale.h> +#include <stdlib.h> + +#define __STDC_FORMAT_MACROS + +static int _pow(int b, int ex) +{ + if (ex == 0) return 1; + int res = b; + while (--ex > 0) res *= b; + return res; +} + +static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) +{ + setlocale(LC_ALL, ""); + switch (cbor_typeof(item)) { + case CBOR_TYPE_UINT: { + fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " "); + fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); + fprintf(out, "Value: %"PRIu64"\n", cbor_get_int(item)); + break; + }; + case CBOR_TYPE_NEGINT: { + fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " "); + fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); + fprintf(out, "Value: -%"PRIu64" -1\n", cbor_get_int(item)); + break; + }; + case CBOR_TYPE_BYTESTRING: { + fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " "); + if (cbor_bytestring_is_indefinite(item)) { + fprintf(out, + "Indefinite, with %zu chunks:\n", + cbor_bytestring_chunk_count(item)); + for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) + _cbor_nested_describe( + cbor_bytestring_chunks_handle(item)[i], + out, + indent + 4); + } else { + fprintf(out, + "Definite, length %zuB\n", + cbor_bytestring_length(item)); + } + break; + }; + case CBOR_TYPE_STRING: { + fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " "); + if (cbor_string_is_indefinite(item)) { + fprintf(out, + "Indefinite, with %zu chunks:\n", + cbor_string_chunk_count(item)); + for (size_t i = 0; i < cbor_string_chunk_count(item); i++) + _cbor_nested_describe( + cbor_string_chunks_handle(item)[i], + out, + indent + 4); + } else { + fprintf(out, + "Definite, length %zuB, %zu codepoints\n", + cbor_string_length(item), + cbor_string_codepoint_count(item)); + /* Careful - this doesn't support multibyte characters! */ + /* Printing those is out of the scope of this demo :) */ + /* libICU is your friend */ + fprintf(out, "%*s", indent + 4, " "); + /* XXX: no null at the end -> confused vprintf */ + fwrite(cbor_string_handle(item), (int) cbor_string_length(item), 1, out); + fprintf(out, "\n"); + } + break; + }; + case CBOR_TYPE_ARRAY: { + fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " "); + if (cbor_array_is_definite(item)) { + fprintf(out, + "Definite, size: %zu\n", + cbor_array_size(item)); + } else { + fprintf(out, + "Indefinite, size: %zu\n", + cbor_array_size(item)); + } + + for (size_t i = 0; i < cbor_array_size(item); i++) + _cbor_nested_describe( + cbor_array_handle(item)[i], + out, + indent + 4); + break; + }; + case CBOR_TYPE_MAP: { + fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " "); + if (cbor_map_is_definite(item)) { + fprintf(out, + "Definite, size: %zu\n", + cbor_map_size(item)); + } else { + fprintf(out, + "Indefinite, size: %zu\n", + cbor_map_size(item)); + } + + for (size_t i = 0; i < cbor_map_size(item); i++) { + _cbor_nested_describe( + cbor_map_handle(item)[i].key, + out, + indent + 4); + _cbor_nested_describe( + cbor_map_handle(item)[i].value, + out, + indent + 4); + } + break; + }; + case CBOR_TYPE_TAG: { + fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " "); + fprintf(out, "Value: %"PRIu64"\n", cbor_tag_value(item)); + _cbor_nested_describe(cbor_tag_item(item), out, indent + 4); + break; + }; + case CBOR_TYPE_FLOAT_CTRL: { + fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " "); + if (cbor_float_ctrl_is_ctrl(item)) { + if (cbor_is_bool(item)) + fprintf(out, "Bool: %s\n", cbor_ctrl_is_bool(item) ? "true" : "false"); + else if (cbor_is_undef(item)) + fprintf(out, "Undefined\n"); + else if (cbor_is_null(item)) + fprintf(out, "Null\n"); + else + fprintf(out, "Simple value %d\n", cbor_ctrl_value(item)); + } else { + fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item))); + fprintf(out, "value: %lf\n", cbor_float_get_float(item)); + } + break; + }; + } +} + +void cbor_describe(cbor_item_t *item, FILE *out) +{ + _cbor_nested_describe(item, out, 0); +} + +#endif diff --git a/lib/libcbor/src/cbor.h b/lib/libcbor/src/cbor.h new file mode 100644 index 00000000000..b8a857e2c67 --- /dev/null +++ b/lib/libcbor/src/cbor.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + + +#ifndef LIBCBOR_H_ +#define LIBCBOR_H_ + +#include "cbor/data.h" +#include "cbor/common.h" + +#include "cbor/arrays.h" +#include "cbor/bytestrings.h" +#include "cbor/floats_ctrls.h" +#include "cbor/ints.h" +#include "cbor/maps.h" +#include "cbor/strings.h" +#include "cbor/tags.h" + +#include "cbor/encoding.h" +#include "cbor/serialization.h" +#include "cbor/callbacks.h" +#include "cbor/streaming.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* High level decoding +* ============================================================================ +*/ + +/** Loads data item from a buffer + * + * @param source The buffer + * @param source_size + * @param result[out] Result indicator. #CBOR_ERR_NONE on success + * @return **new** CBOR item or `NULL` on failure. In that case, \p result contains location and description of the error. + */ +cbor_item_t * cbor_load(cbor_data source, + size_t source_size, + struct cbor_load_result * result); + +/** Deep copy of an item + * + * All the reference counts in the new structure are set to one. + * + * @param item[borrow] item to copy + * @return **new** CBOR deep copy + */ +cbor_item_t * cbor_copy(cbor_item_t * item); + +#if CBOR_PRETTY_PRINTER +#include <stdio.h> + +void cbor_describe(cbor_item_t * item, FILE * out); +#endif + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_H_ diff --git a/lib/libcbor/src/cbor/arrays.c b/lib/libcbor/src/cbor/arrays.c new file mode 100644 index 00000000000..4e3f0b67cf3 --- /dev/null +++ b/lib/libcbor/src/cbor/arrays.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <string.h> +#include "arrays.h" +#include "internal/memory_utils.h" + +size_t cbor_array_size(const cbor_item_t *item) +{ + assert(cbor_isa_array(item)); + return item->metadata.array_metadata.end_ptr; +} + +size_t cbor_array_allocated(const cbor_item_t * item) +{ + assert(cbor_isa_array(item)); + return item->metadata.array_metadata.allocated; +} + + +cbor_item_t * cbor_array_get(const cbor_item_t * item, size_t index) +{ + return cbor_incref(((cbor_item_t **) item->data)[index]); +} + +bool cbor_array_set(cbor_item_t * item, size_t index, cbor_item_t * value) +{ + if (index == item->metadata.array_metadata.end_ptr) { + return cbor_array_push(item, value); + } else if (index < item->metadata.array_metadata.end_ptr) { + return cbor_array_replace(item, index, value); + } else { + return false; + } + return true; +} + +bool cbor_array_replace(cbor_item_t * item, size_t index, cbor_item_t * value) +{ + if (index >= item->metadata.array_metadata.end_ptr) + return false; + /* We cannot use cbor_array_get as that would increase the refcount */ + cbor_intermediate_decref(((cbor_item_t **) item->data)[index]); + ((cbor_item_t **) item->data)[index] = cbor_incref(value); + return true; +} + +bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) +{ + assert(cbor_isa_array(array)); + struct _cbor_array_metadata *metadata = (struct _cbor_array_metadata *) &array->metadata; + cbor_item_t **data = (cbor_item_t **) array->data; + if (cbor_array_is_definite(array)) { + /* Do not reallocate definite arrays */ + if (metadata->end_ptr >= metadata->allocated) { + return false; + } + data[metadata->end_ptr++] = pushee; + } else { + /* Exponential realloc */ + if (metadata->end_ptr >= metadata->allocated) { + // Check for overflows first + if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) { + return false; + } + + size_t new_allocation = metadata->allocated == 0 ? 1 : CBOR_BUFFER_GROWTH * metadata->allocated; + + unsigned char * new_data = _cbor_realloc_multiple(array->data, sizeof(cbor_item_t *), new_allocation); + if (new_data == NULL) { + return false; + } + + array->data = new_data; + metadata->allocated = new_allocation; + } + ((cbor_item_t **)array->data)[metadata->end_ptr++] = pushee; + } + cbor_incref(pushee); + return true; +} + + +bool cbor_array_is_definite(const cbor_item_t *item) +{ + assert(cbor_isa_array(item)); + return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE; +} + +bool cbor_array_is_indefinite(const cbor_item_t *item) +{ + assert(cbor_isa_array(item)); + return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE; +} + +cbor_item_t **cbor_array_handle(const cbor_item_t *item) +{ + assert(cbor_isa_array(item)); + return (cbor_item_t **) item->data; +} + +cbor_item_t *cbor_new_definite_array(size_t size) +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + if (item == NULL) { + return NULL; + } + + cbor_item_t ** data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size); + if (data == NULL) { + _CBOR_FREE(item); + return NULL; + } + + for (size_t i = 0; i < size; i++) + data[i] = NULL; + + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_ARRAY, + .metadata = { + .array_metadata = { + .type = _CBOR_METADATA_DEFINITE, + .allocated = size, + .end_ptr = 0 + } + }, + .data = (unsigned char *)data + }; + + return item; +} + +cbor_item_t *cbor_new_indefinite_array() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + if (item == NULL) + return NULL; + + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_ARRAY, + .metadata = { + .array_metadata = { + .type = _CBOR_METADATA_INDEFINITE, + .allocated = 0, + .end_ptr = 0 + } + }, + .data = NULL /* Can be safely realloc-ed */ + }; + return item; +} diff --git a/lib/libcbor/src/cbor/arrays.h b/lib/libcbor/src/cbor/arrays.h new file mode 100644 index 00000000000..62629f4e1c6 --- /dev/null +++ b/lib/libcbor/src/cbor/arrays.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_ARRAYS_H +#define LIBCBOR_ARRAYS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Get the number of members + * + * @param item[borrow] An array + * @return The number of members + */ +size_t cbor_array_size(const cbor_item_t * item); + +/** Get the size of the allocated storage + * + * @param item[borrow] An array + * @return The size of the allocated storage (number of items) + */ +size_t cbor_array_allocated(const cbor_item_t * item); + +/** Get item by index + * + * @param item[borrow] An array + * @param index The index + * @return **incref** The item, or `NULL` in case of boundary violation + */ +cbor_item_t * cbor_array_get(const cbor_item_t * item, size_t index); + +/** Set item by index + * + * Creating arrays with holes is not possible + * + * @param item[borrow] An array + * @param value[incref] The item to assign + * @param index The index, first item is 0. + * @return true on success, false on allocation failure. + */ +bool cbor_array_set(cbor_item_t * item, size_t index, cbor_item_t * value); + +/** Replace item at an index + * + * The item being replace will be #cbor_decref 'ed. + * + * @param item[borrow] An array + * @param value[incref] The item to assign + * @param index The index, first item is 0. + * @return true on success, false on allocation failure. + */ +bool cbor_array_replace(cbor_item_t * item, size_t index, cbor_item_t * value); + +/** Is the array definite? + * + * @param item[borrow] An array + * @return Is the array definite? + */ +bool cbor_array_is_definite(const cbor_item_t * item); + +/** Is the array indefinite? + * + * @param item[borrow] An array + * @return Is the array indefinite? + */ +bool cbor_array_is_indefinite(const cbor_item_t * item); + +/** Get the array contents + * + * The items may be reordered and modified as long as references remain consistent. + * + * @param item[borrow] An array + * @return #cbor_array_size items + */ +cbor_item_t ** cbor_array_handle(const cbor_item_t * item); + +/** Create new definite array + * + * @param size Number of slots to preallocate + * @return **new** array or `NULL` upon malloc failure + */ +cbor_item_t * cbor_new_definite_array(size_t size); + +/** Create new indefinite array + * + * @return **new** array or `NULL` upon malloc failure + */ +cbor_item_t * cbor_new_indefinite_array(); + +/** Append to the end + * + * For indefinite items, storage may be realloacted. For definite items, only the + * preallocated capacity is available. + * + * @param array[borrow] An array + * @param pushee[incref] The item to push + * @return true on success, false on failure + */ +bool cbor_array_push(cbor_item_t * array, cbor_item_t * pushee); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_ARRAYS_H diff --git a/lib/libcbor/src/cbor/bytestrings.c b/lib/libcbor/src/cbor/bytestrings.c new file mode 100644 index 00000000000..ada4832f0d9 --- /dev/null +++ b/lib/libcbor/src/cbor/bytestrings.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <string.h> +#include "bytestrings.h" +#include "internal/memory_utils.h" + +size_t cbor_bytestring_length(const cbor_item_t *item) +{ + assert(cbor_isa_bytestring(item)); + return item->metadata.bytestring_metadata.length; +} + +unsigned char *cbor_bytestring_handle(const cbor_item_t *item) +{ + assert(cbor_isa_bytestring(item)); + return item->data; +} + +bool cbor_bytestring_is_definite(const cbor_item_t *item) +{ + assert(cbor_isa_bytestring(item)); + return item->metadata.bytestring_metadata.type == _CBOR_METADATA_DEFINITE; +} + +bool cbor_bytestring_is_indefinite(const cbor_item_t *item) +{ + return !cbor_bytestring_is_definite(item); +} + +cbor_item_t *cbor_new_definite_bytestring() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_BYTESTRING, + .metadata = {.bytestring_metadata = {_CBOR_METADATA_DEFINITE, 0}} + }; + return item; +} + +cbor_item_t *cbor_new_indefinite_bytestring() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_BYTESTRING, + .metadata = {.bytestring_metadata = {.type = _CBOR_METADATA_INDEFINITE, .length = 0}}, + .data = _CBOR_MALLOC(sizeof(struct cbor_indefinite_string_data)) + }; + *((struct cbor_indefinite_string_data *) item->data) = (struct cbor_indefinite_string_data) { + .chunk_count = 0, + .chunk_capacity = 0, + .chunks = NULL, + }; + return item; +} + +cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length) +{ + cbor_item_t *res = cbor_new_definite_bytestring(); + void * content = _CBOR_MALLOC(length); + memcpy(content, handle, length); + cbor_bytestring_set_handle(res, content, length); + return res; +} + +void cbor_bytestring_set_handle(cbor_item_t *item, cbor_mutable_data CBOR_RESTRICT_POINTER data, size_t length) +{ + assert(cbor_isa_bytestring(item)); + assert(cbor_bytestring_is_definite(item)); + item->data = data; + item->metadata.bytestring_metadata.length = length; +} + +cbor_item_t **cbor_bytestring_chunks_handle(const cbor_item_t *item) +{ + assert(cbor_isa_bytestring(item)); + assert(cbor_bytestring_is_indefinite(item)); + return ((struct cbor_indefinite_string_data *) item->data)->chunks; +} + +size_t cbor_bytestring_chunk_count(const cbor_item_t *item) +{ + assert(cbor_isa_bytestring(item)); + assert(cbor_bytestring_is_indefinite(item)); + return ((struct cbor_indefinite_string_data *) item->data)->chunk_count; + +} + +bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk) +{ + assert(cbor_isa_bytestring(item)); + assert(cbor_bytestring_is_indefinite(item)); + struct cbor_indefinite_string_data *data = (struct cbor_indefinite_string_data *) item->data; + if (data->chunk_count == data->chunk_capacity) { + /* We need more space */ + if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) { + return false; + } + + data->chunk_capacity = data->chunk_capacity == 0 ? 1 : CBOR_BUFFER_GROWTH * (data->chunk_capacity); + + cbor_item_t **new_chunks_data = _cbor_realloc_multiple(data->chunks, sizeof(cbor_item_t *), data->chunk_capacity); + + if (new_chunks_data == NULL) { + return false; + } + + data->chunks = new_chunks_data; + } + data->chunks[data->chunk_count++] = cbor_incref(chunk); + return true; +} diff --git a/lib/libcbor/src/cbor/bytestrings.h b/lib/libcbor/src/cbor/bytestrings.h new file mode 100644 index 00000000000..a5eb98b5e7e --- /dev/null +++ b/lib/libcbor/src/cbor/bytestrings.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_BYTESTRINGS_H +#define LIBCBOR_BYTESTRINGS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* Byte string manipulation +* ============================================================================ +*/ + +/** Returns the length of the binary data + * + * For definite byte strings only + * + * @param item[borrow] a definite bytestring + * @return length of the binary data. Zero if no chunk has been attached yet + */ +size_t cbor_bytestring_length(const cbor_item_t *item); + +/** Is the byte string definite? + * + * @param item[borrow] a byte string + * @return Is the byte string definite? + */ +bool cbor_bytestring_is_definite(const cbor_item_t *item); + +/** Is the byte string indefinite? + * + * @param item[borrow] a byte string + * @return Is the byte string indefinite? + */ +bool cbor_bytestring_is_indefinite(const cbor_item_t *item); + +/** Get the handle to the binary data + * + * Definite items only. Modifying the data is allowed. In that case, the caller takes + * responsibility for the effect on items this item might be a part of + * + * @param item[borrow] A definite byte string + * @return The address of the binary data. `NULL` if no data have been assigned yet. + */ +cbor_mutable_data cbor_bytestring_handle(const cbor_item_t *item); + +/** Set the handle to the binary data + * + * @param item[borrow] A definite byte string + * @param data The memory block. The caller gives up the ownership of the block. libcbor will deallocate it when appropriate using its free function + * @param length Length of the data block + */ +void cbor_bytestring_set_handle(cbor_item_t *item, cbor_mutable_data CBOR_RESTRICT_POINTER data, size_t length); + +/** Get the handle to the array of chunks + * + * Manipulations with the memory block (e.g. sorting it) are allowed, but the validity and the number of chunks must be retained. + * + * @param item[borrow] A indefinite byte string + * @return array of #cbor_bytestring_chunk_count definite bytestrings + */ +cbor_item_t **cbor_bytestring_chunks_handle(const cbor_item_t *item); + +/** Get the number of chunks this string consist of + * + * @param item[borrow] A indefinite bytestring + * @return The chunk count. 0 for freshly created items. + */ +size_t cbor_bytestring_chunk_count(const cbor_item_t *item); + +/** Appends a chunk to the bytestring + * + * Indefinite byte strings only. + * + * May realloc the chunk storage. + * + * @param item[borrow] An indefinite byte string + * @param item[incref] A definite byte string + * @return true on success, false on realloc failure. In that case, the refcount of `chunk` is not increased and the `item` is left intact. + */ +bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk); + +/** Creates a new definite byte string + * + * The handle is initialized to `NULL` and length to 0 + * + * @return **new** definite bytestring. `NULL` on malloc failure. + */ +cbor_item_t *cbor_new_definite_bytestring(); + +/** Creates a new indefinite byte string + * + * The chunks array is initialized to `NULL` and chunkcount to 0 + * + * @return **new** indefinite bytestring. `NULL` on malloc failure. + */ +cbor_item_t *cbor_new_indefinite_bytestring(); + +/** Creates a new byte string and initializes it + * + * The `handle` will be copied to a newly allocated block + * + * @param handle Block of binary data + * @param length Length of `data` + * @return A **new** byte string with content `handle`. `NULL` on malloc failure. + */ +cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length); + +#ifdef __cplusplus +} +#endif + + +#endif //LIBCBOR_BYTESTRINGS_H diff --git a/lib/libcbor/src/cbor/callbacks.c b/lib/libcbor/src/cbor/callbacks.c new file mode 100644 index 00000000000..81fe857319e --- /dev/null +++ b/lib/libcbor/src/cbor/callbacks.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "callbacks.h" + +#define CBOR_DUMMY_CALLBACK { } + +void cbor_null_uint8_callback(void *_ctx, uint8_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_uint16_callback(void *_ctx, uint16_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_uint32_callback(void *_ctx, uint32_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_uint64_callback(void *_ctx, uint64_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_negint8_callback(void *_ctx, uint8_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_negint16_callback(void *_ctx, uint16_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_negint32_callback(void *_ctx, uint32_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_negint64_callback(void *_ctx, uint64_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_string_callback(void *_ctx, cbor_data _val, size_t _val2) CBOR_DUMMY_CALLBACK + +void cbor_null_string_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +void cbor_null_byte_string_callback(void *_ctx, cbor_data _val, size_t _val2) CBOR_DUMMY_CALLBACK + +void cbor_null_byte_string_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +void cbor_null_array_start_callback(void *_ctx, size_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_indef_array_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +void cbor_null_map_start_callback(void *_ctx, size_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_indef_map_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +void cbor_null_tag_callback(void *_ctx, uint64_t _val) CBOR_DUMMY_CALLBACK + +void cbor_null_float2_callback(void *_ctx, float _val) CBOR_DUMMY_CALLBACK + +void cbor_null_float4_callback(void *_ctx, float _val) CBOR_DUMMY_CALLBACK + +void cbor_null_float8_callback(void *_ctx, double _val) CBOR_DUMMY_CALLBACK + +void cbor_null_null_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +void cbor_null_undefined_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +void cbor_null_boolean_callback(void *_ctx, bool _val) CBOR_DUMMY_CALLBACK + +void cbor_null_indef_break_callback(void *_ctx) CBOR_DUMMY_CALLBACK + +const struct cbor_callbacks cbor_empty_callbacks = { + /* Type 0 - Unsigned integers */ + .uint8 = cbor_null_uint8_callback, + .uint16 = cbor_null_uint16_callback, + .uint32 = cbor_null_uint32_callback, + .uint64 = cbor_null_uint64_callback, + + /* Type 1 - Negative integers */ + .negint8 = cbor_null_negint8_callback, + .negint16 = cbor_null_negint16_callback, + .negint32 = cbor_null_negint32_callback, + .negint64 = cbor_null_negint64_callback, + + /* Type 2 - Byte strings */ + .byte_string_start = cbor_null_byte_string_start_callback, + .byte_string = cbor_null_byte_string_callback, + + /* Type 3 - Strings */ + .string_start = cbor_null_string_start_callback, + .string = cbor_null_string_callback, + + /* Type 4 - Arrays */ + .indef_array_start = cbor_null_indef_array_start_callback, + .array_start = cbor_null_array_start_callback, + + /* Type 5 - Maps */ + .indef_map_start = cbor_null_indef_map_start_callback, + .map_start = cbor_null_map_start_callback, + + /* Type 6 - Tags */ + .tag = cbor_null_tag_callback, + + /* Type 7 - Floats & misc */ + /* Type names cannot be member names */ + .float2 = cbor_null_float2_callback, + /* 2B float is not supported in standard C */ + .float4 = cbor_null_float4_callback, + .float8 = cbor_null_float8_callback, + .undefined = cbor_null_undefined_callback, + .null = cbor_null_null_callback, + .boolean = cbor_null_boolean_callback, + + /* Shared indefinites */ + .indef_break = cbor_null_indef_break_callback, +}; diff --git a/lib/libcbor/src/cbor/callbacks.h b/lib/libcbor/src/cbor/callbacks.h new file mode 100644 index 00000000000..7ca6cda9ea5 --- /dev/null +++ b/lib/libcbor/src/cbor/callbacks.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_CALLBACKS_H +#define LIBCBOR_CALLBACKS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Callback prototype */ +typedef void(*cbor_int8_callback)(void *, uint8_t); + +/** Callback prototype */ +typedef void(*cbor_int16_callback)(void *, uint16_t); + +/** Callback prototype */ +typedef void(*cbor_int32_callback)(void *, uint32_t); + +/** Callback prototype */ +typedef void(*cbor_int64_callback)(void *, uint64_t); + +/** Callback prototype */ +typedef void(*cbor_simple_callback)(void *); + +/** Callback prototype */ +typedef void(*cbor_string_callback)(void *, cbor_data, size_t); + +/** Callback prototype */ +typedef void(*cbor_collection_callback)(void *, size_t); + +/** Callback prototype */ +typedef void(*cbor_float_callback)(void *, float); + +/** Callback prototype */ +typedef void(*cbor_double_callback)(void *, double); + +/** Callback prototype */ +typedef void(*cbor_bool_callback)(void *, bool); + +/** Callback bundle -- passed to the decoder */ +struct cbor_callbacks { + /** Unsigned int */ + cbor_int8_callback uint8; + /** Unsigned int */ + cbor_int16_callback uint16; + /** Unsigned int */ + cbor_int32_callback uint32; + /** Unsigned int */ + cbor_int64_callback uint64; + + /** Negative int */ + cbor_int64_callback negint64; + /** Negative int */ + cbor_int32_callback negint32; + /** Negative int */ + cbor_int16_callback negint16; + /** Negative int */ + cbor_int8_callback negint8; + + /** Definite byte string */ + cbor_simple_callback byte_string_start; + /** Indefinite byte string start */ + cbor_string_callback byte_string; + + /** Definite string */ + cbor_string_callback string; + /** Indefinite string start */ + cbor_simple_callback string_start; + + /** Definite array */ + cbor_simple_callback indef_array_start; + /** Indefinite array */ + cbor_collection_callback array_start; + + /** Definite map */ + cbor_simple_callback indef_map_start; + /** Indefinite map */ + cbor_collection_callback map_start; + + /** Tags */ + cbor_int64_callback tag; + + /** Half float */ + cbor_float_callback float2; + /** Single float */ + cbor_float_callback float4; + /** Double float */ + cbor_double_callback float8; + /** Undef */ + cbor_simple_callback undefined; + /** Null */ + cbor_simple_callback null; + /** Bool */ + cbor_bool_callback boolean; + + /** Indefinite item break */ + cbor_simple_callback indef_break; +}; + +/** Dummy callback implementation - does nothing */ +void cbor_null_uint8_callback(void *, uint8_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_uint16_callback(void *, uint16_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_uint32_callback(void *, uint32_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_uint64_callback(void *, uint64_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_negint8_callback(void *, uint8_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_negint16_callback(void *, uint16_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_negint32_callback(void *, uint32_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_negint64_callback(void *, uint64_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_string_callback(void *, cbor_data, size_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_string_start_callback(void *); + +/** Dummy callback implementation - does nothing */ +void cbor_null_byte_string_callback(void *, cbor_data, size_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_byte_string_start_callback(void *); + +/** Dummy callback implementation - does nothing */ +void cbor_null_array_start_callback(void *, size_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_indef_array_start_callback(void *); + +/** Dummy callback implementation - does nothing */ +void cbor_null_map_start_callback(void *, size_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_indef_map_start_callback(void *); + +/** Dummy callback implementation - does nothing */ +void cbor_null_tag_callback(void *, uint64_t); + +/** Dummy callback implementation - does nothing */ +void cbor_null_float2_callback(void *, float); + +/** Dummy callback implementation - does nothing */ +void cbor_null_float4_callback(void *, float); + +/** Dummy callback implementation - does nothing */ +void cbor_null_float8_callback(void *, double); + +/** Dummy callback implementation - does nothing */ +void cbor_null_null_callback(void *); + +/** Dummy callback implementation - does nothing */ +void cbor_null_undefined_callback(void *); + +/** Dummy callback implementation - does nothing */ +void cbor_null_boolean_callback(void *, bool); + +/** Dummy callback implementation - does nothing */ +void cbor_null_indef_break_callback(void *); + +/** Dummy callback bundle - does nothing */ +extern const struct cbor_callbacks cbor_empty_callbacks; + +#ifdef __cplusplus +} +#endif + + +#endif //LIBCBOR_CALLBACKS_H diff --git a/lib/libcbor/src/cbor/common.c b/lib/libcbor/src/cbor/common.c new file mode 100644 index 00000000000..77544ae8107 --- /dev/null +++ b/lib/libcbor/src/cbor/common.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "cbor/common.h" +#include "arrays.h" +#include "bytestrings.h" +#include "data.h" +#include "floats_ctrls.h" +#include "ints.h" +#include "maps.h" +#include "strings.h" +#include "tags.h" + +bool cbor_isa_uint(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_UINT; +} + +bool cbor_isa_negint(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_NEGINT; +} + +bool cbor_isa_bytestring(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_BYTESTRING; +} + +bool cbor_isa_string(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_STRING; +} + +bool cbor_isa_array(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_ARRAY; +} + +bool cbor_isa_map(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_MAP; +} + +bool cbor_isa_tag(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_TAG; +} + +bool cbor_isa_float_ctrl(const cbor_item_t *item) +{ + return item->type == CBOR_TYPE_FLOAT_CTRL; +} + + +cbor_type cbor_typeof(const cbor_item_t *item) +{ + return item->type; +} + + +bool cbor_is_int(const cbor_item_t *item) +{ + return cbor_isa_uint(item) || cbor_isa_negint(item); +} + + +bool cbor_is_bool(const cbor_item_t *item) +{ + return cbor_isa_float_ctrl(item) && + (cbor_ctrl_value(item) == CBOR_CTRL_FALSE || cbor_ctrl_value(item) == CBOR_CTRL_TRUE); +} + +bool cbor_is_null(const cbor_item_t *item) +{ + return cbor_isa_float_ctrl(item) && cbor_ctrl_value(item) == CBOR_CTRL_NULL; +} + +bool cbor_is_undef(const cbor_item_t *item) +{ + return cbor_isa_float_ctrl(item) && cbor_ctrl_value(item) == CBOR_CTRL_UNDEF; +} + +bool cbor_is_float(const cbor_item_t *item) +{ + return cbor_isa_float_ctrl(item) && !cbor_float_ctrl_is_ctrl(item); +} + + +cbor_item_t * cbor_incref(cbor_item_t *item) +{ + item->refcount++; + return item; +} + +void cbor_decref(cbor_item_t **item_ref) +{ + cbor_item_t * item = *item_ref; + if (--item->refcount == 0) { + switch (item->type) { + case CBOR_TYPE_UINT: + /* Fallthrough */ + case CBOR_TYPE_NEGINT: + /* Combined allocation, freeing the item suffices */ + { + break; + } + case CBOR_TYPE_BYTESTRING: { + if (cbor_bytestring_is_definite(item)) { + _CBOR_FREE(item->data); + } else { + /* We need to decref all chunks */ + cbor_item_t **handle = cbor_bytestring_chunks_handle(item); + for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) + cbor_decref(&handle[i]); + _CBOR_FREE(((struct cbor_indefinite_string_data *) item->data)->chunks); + _CBOR_FREE(item->data); + } + break; + } + case CBOR_TYPE_STRING: { + if (cbor_string_is_definite(item)) { + _CBOR_FREE(item->data); + } else { + /* We need to decref all chunks */ + cbor_item_t **handle = cbor_string_chunks_handle(item); + for (size_t i = 0; i < cbor_string_chunk_count(item); i++) + cbor_decref(&handle[i]); + _CBOR_FREE(((struct cbor_indefinite_string_data *) item->data)->chunks); + _CBOR_FREE(item->data); + } + break; + } + case CBOR_TYPE_ARRAY: { + /* Get all items and decref them */ + cbor_item_t **handle = cbor_array_handle(item); + size_t size = cbor_array_size(item); + for (size_t i = 0; i < size; i++) + if (handle[i] != NULL) + cbor_decref(&handle[i]); + _CBOR_FREE(item->data); + break; + } + case CBOR_TYPE_MAP: { + struct cbor_pair *handle = cbor_map_handle(item); + for (size_t i = 0; i < item->metadata.map_metadata.end_ptr; i++, handle++) { + cbor_decref(&handle->key); + if (handle->value != NULL) + cbor_decref(&handle->value); + } + _CBOR_FREE(item->data); + break; + }; + case CBOR_TYPE_TAG: { + if (item->metadata.tag_metadata.tagged_item != NULL) + cbor_decref(&item->metadata.tag_metadata.tagged_item); + _CBOR_FREE(item->data); + break; + } + case CBOR_TYPE_FLOAT_CTRL: { + /* Floats have combined allocation */ + break; + } + } + _CBOR_FREE(item); + //TODO + *item_ref = NULL; + } +} + +void cbor_intermediate_decref(cbor_item_t * item) +{ + cbor_decref(&item); +} + +size_t cbor_refcount(const cbor_item_t * item) +{ + return item->refcount; +} + +cbor_item_t * cbor_move(cbor_item_t * item) +{ + item->refcount--; + return item; +} diff --git a/lib/libcbor/src/cbor/common.h b/lib/libcbor/src/cbor/common.h new file mode 100644 index 00000000000..9e0b63c4a6f --- /dev/null +++ b/lib/libcbor/src/cbor/common.h @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2014-2015 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_COMMON_H +#define LIBCBOR_COMMON_H + +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <assert.h> +#include "data.h" +#include "cbor/configuration.h" + +#ifdef __cplusplus +extern "C" { + +/** C++ is not a subset of C99 -- 'restrict' qualifier is not a part of the language. + * This is a workaround to keep it in C headers -- compilers allow linking non-restrict + * signatures with restrict implementations. + * + * If you know a nicer way, please do let me know. + */ +#define CBOR_RESTRICT_POINTER + +#else + +// MSVC + C++ workaround +#define CBOR_RESTRICT_POINTER CBOR_RESTRICT_SPECIFIER + +#endif + +static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION; +static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION; +static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION; + +#define CBOR_VERSION TO_STR(CBOR_MAJOR_VERSION) "." TO_STR(CBOR_MINOR_VERSION) "." TO_STR(CBOR_PATCH_VERSION) +#define CBOR_HEX_VERSION ((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION) + + +/* http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing */ +#ifdef DEBUG +#include <stdio.h> +#define debug_print(fmt, ...) do { \ + if (DEBUG) \ + fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); \ + } while (0) +#else +#define debug_print(fmt, ...) do {} while (0) +#endif + +#define TO_STR_(x) #x +#define TO_STR(x) TO_STR_(x) /* enables proper double expansion */ + +#if CBOR_CUSTOM_ALLOC + +typedef void * (* _cbor_malloc_t)(size_t); +typedef void * (* _cbor_realloc_t)(void *, size_t); +typedef void (* _cbor_free_t)(void *); + +extern _cbor_malloc_t _cbor_malloc; +extern _cbor_realloc_t _cbor_realloc; +extern _cbor_free_t _cbor_free; + +/** Sets the memory management routines to use. + * + * Only available when CBOR_CUSTOM_ALLOC is truthy + * + * \rst + * .. warning:: This function modifies the global state and should therefore be used accordingly. Changing the memory handlers while allocated items exist will result in a ``free``/``malloc`` mismatch. This function is not thread safe with respect to both itself and all the other *libcbor* functions that work with the heap. + * .. note:: `realloc` implementation must correctly support `NULL` reallocation + * \endrst + * + * @param custom_malloc malloc implementation + * @param custom_realloc realloc implementation + * @param custom_free free implementation + */ +void cbor_set_allocs(_cbor_malloc_t custom_malloc, _cbor_realloc_t custom_realloc, _cbor_free_t custom_free); + +#define _CBOR_MALLOC _cbor_malloc +#define _CBOR_REALLOC _cbor_realloc +#define _CBOR_FREE _cbor_free + +#else + +#define _CBOR_MALLOC malloc +#define _CBOR_REALLOC realloc +#define _CBOR_FREE free + +#endif + +/* +* ============================================================================ +* Type manipulation +* ============================================================================ +*/ + +/** Get the type of the item + * + * @param item[borrow] + * @return The type + */ +cbor_type cbor_typeof(const cbor_item_t * item); /* Will be inlined iff link-time opt is enabled */ + +/* Standard item types as described by the RFC */ + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item an #CBOR_TYPE_UINT? + */ +bool cbor_isa_uint(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item a #CBOR_TYPE_NEGINT? + */ +bool cbor_isa_negint(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item a #CBOR_TYPE_BYTESTRING? + */ +bool cbor_isa_bytestring(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item a #CBOR_TYPE_STRING? + */ +bool cbor_isa_string(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item an #CBOR_TYPE_ARRAY? + */ +bool cbor_isa_array(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item a #CBOR_TYPE_MAP? + */ +bool cbor_isa_map(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item a #CBOR_TYPE_TAG? + */ +bool cbor_isa_tag(const cbor_item_t * item); + +/** Does the item have the appropriate major type? + * @param item[borrow] the item + * @return Is the item a #CBOR_TYPE_FLOAT_CTRL? + */ +bool cbor_isa_float_ctrl(const cbor_item_t * item); + +/* Practical types with respect to their semantics (but not tag values) */ + +/** Is the item an integer, either positive or negative? + * @param item[borrow] the item + * @return Is the item an integer, either positive or negative? + */ +bool cbor_is_int(const cbor_item_t * item); + +/** Is the item an a floating point number? + * @param item[borrow] the item + * @return Is the item a floating point number? + */ +bool cbor_is_float(const cbor_item_t * item); + +/** Is the item an a boolean? + * @param item[borrow] the item + * @return Is the item a boolean? + */ +bool cbor_is_bool(const cbor_item_t * item); + +/** Does this item represent `null` + * \rst + * .. warning:: This is in no way related to the value of the pointer. Passing a null pointer will most likely result in a crash. + * \endrst + * @param item[borrow] the item + * @return Is the item (CBOR logical) null? + */ +bool cbor_is_null(const cbor_item_t * item); + + +/** Does this item represent `undefined` + * \rst + * .. warning:: Care must be taken to distinguish nulls and undefined values in C. + * \endrst + * @param item[borrow] the item + * @return Is the item (CBOR logical) undefined? + */ +bool cbor_is_undef(const cbor_item_t * item); + + +/* +* ============================================================================ +* Memory management +* ============================================================================ +*/ + +/** Increases the reference count by one + * + * No dependent items are affected. + * + * @param item[incref] item the item + * @return the input reference + */ +cbor_item_t * cbor_incref(cbor_item_t * item); + +/** Decreases the reference count by one, deallocating the item if needed + * + * In case the item is deallocated, the reference count of any dependent items + * is adjusted accordingly in a recursive manner. + * + * @param item[take] the item. Set to `NULL` if deallocated + */ +void cbor_decref(cbor_item_t ** item); + +/** Decreases the reference count by one, deallocating the item if needed + * + * Convenience wrapper for #cbor_decref when its set-to-null behavior is not needed + * + * @param item[take] the item + */ +void cbor_intermediate_decref(cbor_item_t * item); + +/** Get the reference count + * + * \rst + * .. warning:: This does *not* account for transitive references. + * \endrst + * + * @param item[borrow] the item + * @return the reference count + */ +size_t cbor_refcount(const cbor_item_t * item); + +/** Provides CPP-like move construct + * + * Decreases the reference count by one, but does not deallocate the item even if its refcount + * reaches zero. This is useful for passing intermediate values to functions that increase + * reference count. Should only be used with functions that `incref` their arguments. + * + * \rst + * .. warning:: If the item is moved without correctly increasing the reference count afterwards, the memory will be leaked. + * \endrst + * + * @param item[take] the item + * @return the item with reference count decreased by one + */ +cbor_item_t * cbor_move(cbor_item_t * item); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_COMMON_H diff --git a/lib/libcbor/src/cbor/configuration.h b/lib/libcbor/src/cbor/configuration.h new file mode 100644 index 00000000000..3a8adf6a902 --- /dev/null +++ b/lib/libcbor/src/cbor/configuration.h @@ -0,0 +1,15 @@ +#ifndef LIBCBOR_CONFIGURATION_H +#define LIBCBOR_CONFIGURATION_H + +#define CBOR_MAJOR_VERSION 0 +#define CBOR_MINOR_VERSION 5 +#define CBOR_PATCH_VERSION 0 + +#define CBOR_CUSTOM_ALLOC 0 +#define CBOR_BUFFER_GROWTH 2 +#define CBOR_PRETTY_PRINTER 1 + +#define CBOR_RESTRICT_SPECIFIER restrict +#define CBOR_INLINE_SPECIFIER + +#endif //LIBCBOR_CONFIGURATION_H diff --git a/lib/libcbor/src/cbor/configuration.h.in b/lib/libcbor/src/cbor/configuration.h.in new file mode 100644 index 00000000000..b81a0e64185 --- /dev/null +++ b/lib/libcbor/src/cbor/configuration.h.in @@ -0,0 +1,15 @@ +#ifndef LIBCBOR_CONFIGURATION_H +#define LIBCBOR_CONFIGURATION_H + +#define CBOR_MAJOR_VERSION ${CBOR_VERSION_MAJOR} +#define CBOR_MINOR_VERSION ${CBOR_VERSION_MINOR} +#define CBOR_PATCH_VERSION ${CBOR_VERSION_PATCH} + +#cmakedefine01 CBOR_CUSTOM_ALLOC +#define CBOR_BUFFER_GROWTH ${CBOR_BUFFER_GROWTH} +#cmakedefine01 CBOR_PRETTY_PRINTER + +#define CBOR_RESTRICT_SPECIFIER ${CBOR_RESTRICT_SPECIFIER} +#define CBOR_INLINE_SPECIFIER ${CBOR_INLINE_SPECIFIER} + +#endif //LIBCBOR_CONFIGURATION_H diff --git a/lib/libcbor/src/cbor/data.h b/lib/libcbor/src/cbor/data.h new file mode 100644 index 00000000000..91b59db756a --- /dev/null +++ b/lib/libcbor/src/cbor/data.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_DATA_H +#define LIBCBOR_DATA_H + +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef const unsigned char * cbor_data; +typedef unsigned char * cbor_mutable_data; + +/** Specifies the Major type of ::cbor_item_t */ +typedef enum cbor_type { + CBOR_TYPE_UINT /** 0 - positive integers */ + ,CBOR_TYPE_NEGINT /** 1 - negative integers*/ + ,CBOR_TYPE_BYTESTRING /** 2 - byte strings */ + ,CBOR_TYPE_STRING /** 3 - strings */ + ,CBOR_TYPE_ARRAY /** 4 - arrays */ + ,CBOR_TYPE_MAP /** 5 - maps */ + ,CBOR_TYPE_TAG /** 6 - tags */ + ,CBOR_TYPE_FLOAT_CTRL /** 7 - decimals and special values (true, false, nil, ...) */ +} cbor_type; + +/** Possible decoding errors */ +typedef enum { + CBOR_ERR_NONE + ,CBOR_ERR_NOTENOUGHDATA + ,CBOR_ERR_NODATA + ,CBOR_ERR_MALFORMATED + ,CBOR_ERR_MEMERROR /** Memory error - item allocation failed. Is it too big for your allocator? */ + ,CBOR_ERR_SYNTAXERROR /** Stack parsing algorithm failed */ +} cbor_error_code; + +/** Possible widths of #CBOR_TYPE_UINT items */ +typedef enum { + CBOR_INT_8 + ,CBOR_INT_16 + ,CBOR_INT_32 + ,CBOR_INT_64 +} cbor_int_width; + +/** Possible widths of #CBOR_TYPE_FLOAT_CTRL items */ +typedef enum { + CBOR_FLOAT_0 /** Internal use - ctrl and special values */ + ,CBOR_FLOAT_16 /** Half float */ + ,CBOR_FLOAT_32 /** Single float */ + ,CBOR_FLOAT_64 /** Double */ +} cbor_float_width; + +/** Metadata for dynamically sized types */ +typedef enum { + _CBOR_METADATA_DEFINITE + ,_CBOR_METADATA_INDEFINITE +} _cbor_dst_metadata; + +/** Semantic mapping for CTRL simple values */ +typedef enum { + CBOR_CTRL_NONE = 0, + CBOR_CTRL_FALSE = 20, + CBOR_CTRL_TRUE = 21, + CBOR_CTRL_NULL = 22, + CBOR_CTRL_UNDEF = 23 +} _cbor_ctrl; + +/** Integers specific metadata */ +struct _cbor_int_metadata { + cbor_int_width width; +}; + +/** Bytestrings specific metadata */ +struct _cbor_bytestring_metadata { + size_t length; + _cbor_dst_metadata type; +}; + +/** Strings specific metadata */ +struct _cbor_string_metadata { + size_t length; + size_t codepoint_count; /* Sum of chunks' codepoint_counts for indefinite strings */ + _cbor_dst_metadata type; +}; + +/** Arrays specific metadata */ +struct _cbor_array_metadata { + size_t allocated; + size_t end_ptr; + _cbor_dst_metadata type; +}; + +/** Maps specific metadata */ +struct _cbor_map_metadata { + size_t allocated; + size_t end_ptr; + _cbor_dst_metadata type; +}; + +/** Arrays specific metadata + * + * The pointer is included - cbor_item_metadata is + * 2 * sizeof(size_t) + sizeof(_cbor_string_type_metadata), + * lets use the space + */ +struct _cbor_tag_metadata { + struct cbor_item_t * tagged_item; + uint64_t value; +}; + +/** Floats specific metadata - includes CTRL values */ +struct _cbor_float_ctrl_metadata { + cbor_float_width width; + uint8_t ctrl; +}; + +/** Raw memory casts helper */ +union _cbor_float_helper { + float as_float; + uint32_t as_uint; +}; + +/** Raw memory casts helper */ +union _cbor_double_helper { + double as_double; + uint64_t as_uint; +}; + +/** Union of metadata across all possible types - discriminated in #cbor_item_t */ +union cbor_item_metadata { + struct _cbor_int_metadata int_metadata; + struct _cbor_bytestring_metadata bytestring_metadata; + struct _cbor_string_metadata string_metadata; + struct _cbor_array_metadata array_metadata; + struct _cbor_map_metadata map_metadata; + struct _cbor_tag_metadata tag_metadata; + struct _cbor_float_ctrl_metadata float_ctrl_metadata; +}; + +/** The item handle */ +typedef struct cbor_item_t { + /** Discriminated by type */ + union cbor_item_metadata metadata; + /** Reference count - initialize to 0 */ + size_t refcount; + /** Major type discriminator */ + cbor_type type; + /** Raw data block - interpretation depends on metadata */ + unsigned char * data; +} cbor_item_t; + +/** Defines cbor_item_t#data structure for indefinite strings and bytestrings + * + * Used to cast the raw representation for a sane manipulation + */ +struct cbor_indefinite_string_data { + size_t chunk_count; + size_t chunk_capacity; + cbor_item_t * * chunks; +}; + +/** High-level decoding error */ +struct cbor_error { + /** Aproximate position */ + size_t position; + /** Description */ + cbor_error_code code; +}; + +/** Simple pair of items for use in maps */ +struct cbor_pair { + cbor_item_t * key, * value; +}; + +/** High-level decoding result */ +struct cbor_load_result { + /** Error indicator */ + struct cbor_error error; + /** Number of bytes read*/ + size_t read; +}; + + +/** Streaming decoder result - status */ +enum cbor_decoder_status { + CBOR_DECODER_FINISHED /** OK, finished */ + ,CBOR_DECODER_NEDATA /** Not enough data - mismatch with MTB */ + ,CBOR_DECODER_EBUFFER /** Buffer manipulation problem */ + ,CBOR_DECODER_ERROR /** Malformed or reserved MTB/value */ +}; + +/** Streaming decoder result */ +struct cbor_decoder_result { + /** Bytes read */ + size_t read; + /** The result */ + enum cbor_decoder_status status; +}; + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_DATA_H diff --git a/lib/libcbor/src/cbor/encoding.c b/lib/libcbor/src/cbor/encoding.c new file mode 100644 index 00000000000..bb636d82145 --- /dev/null +++ b/lib/libcbor/src/cbor/encoding.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "encoding.h" +#include "internal/encoders.h" + +size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint8(value, buffer, buffer_size, 0x00); +} + +size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint16(value, buffer, buffer_size, 0x00); +} + +size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint32(value, buffer, buffer_size, 0x00); +} + +size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint64(value, buffer, buffer_size, 0x00); +} + +size_t cbor_encode_uint(uint64_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint(value, buffer, buffer_size, 0x00); +} + + +size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint8(value, buffer, buffer_size, 0x20); +} + +size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint16(value, buffer, buffer_size, 0x20); +} + +size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint32(value, buffer, buffer_size, 0x20); +} + +size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint64(value, buffer, buffer_size, 0x20); +} + +size_t cbor_encode_negint(uint64_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint(value, buffer, buffer_size, 0x20); +} + +size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint((size_t) length, buffer, buffer_size, 0x40); +} + +size_t _cbor_encode_byte(uint8_t value, unsigned char *buffer, size_t buffer_size) +{ + if (buffer_size >= 1) { + buffer[0] = value; + return 1; + } else + return 0; +} + +size_t cbor_encode_indef_bytestring_start(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0x5F, buffer, buffer_size); +} + +size_t cbor_encode_string_start(size_t length, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint((size_t) length, buffer, buffer_size, 0x60); +} + +size_t cbor_encode_indef_string_start(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0x7F, buffer, buffer_size); +} + +size_t cbor_encode_array_start(size_t length, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint((size_t) length, buffer, buffer_size, 0x80); +} + +size_t cbor_encode_indef_array_start(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0x9F, buffer, buffer_size); +} + +size_t cbor_encode_map_start(size_t length, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint((size_t) length, buffer, buffer_size, 0xA0); +} + +size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0xBF, buffer, buffer_size); +} + +size_t cbor_encode_tag(uint64_t value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint(value, buffer, buffer_size, 0xC0); +} + +size_t cbor_encode_bool(bool value, unsigned char *buffer, size_t buffer_size) +{ + return value ? _cbor_encode_byte(0xF5, buffer, buffer_size) : _cbor_encode_byte(0xF4, buffer, buffer_size); +} + +size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0xF6, buffer, buffer_size); +} + +size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0xF7, buffer, buffer_size); +} + +size_t cbor_encode_half(float value, unsigned char *buffer, size_t buffer_size) +{ + /* Assuming value is normalized */ + uint32_t val = ((union _cbor_float_helper) {.as_float = value}).as_uint; + uint16_t res; + uint8_t exp = (uint8_t) ((val & 0x7F800000) >> 23); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */ + uint32_t mant = val & 0x7FFFFF; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */ + if (exp == 0xFF) { /* Infinity or NaNs */ + if (value != value) { + res = (uint16_t) 0x00e700; /* Not IEEE semantics - required by CBOR [s. 3.9] */ + } else { + res = (uint16_t) ((val & 0x80000000) >> 16 | 0x7C00 | (mant ? 1 : 0) << 15); + } + } else if (exp == 0x00) { /* Zeroes or subnorms */ + res = (uint16_t) ((val & 0x80000000) >> 16 | mant >> 13); + } else { /* Normal numbers */ + int8_t logical_exp = (int8_t) (exp - 127); + assert(logical_exp == exp - 127); + + // Now we know that 2^exp <= 0 logically + if (logical_exp < -24) { + /* No unambiguous representation exists, this float is not a half float and is too small to + be represented using a half, round off to zero. Consistent with the reference implementation. */ + res = 0; + } else if (logical_exp < -14) { + /* Offset the remaining decimal places by shifting the significand, the value is lost. + This is an implementation decision that works around the absence of standard half-float + in the language. */ + res = (uint16_t) (val & 0x80000000) >> 16 | (uint16_t) (1 << (24 + logical_exp)); + } else { + res = (uint16_t) ((val & 0x80000000) >> 16 | ((((uint8_t) logical_exp) + 15) << 10) | (uint16_t) (mant >> 13)); + } + } + return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0); +} + +size_t cbor_encode_single(float value, unsigned char *buffer, size_t buffer_size) +{ + + return _cbor_encode_uint32(((union _cbor_float_helper) {.as_float = value}).as_uint, buffer, buffer_size, 0xE0); +} + +size_t cbor_encode_double(double value, unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_uint64(((union _cbor_double_helper) {.as_double = value}).as_uint, buffer, buffer_size, 0xE0); +} + +size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) +{ + return _cbor_encode_byte(0xFF, buffer, buffer_size); +} + +size_t cbor_encode_ctrl(uint8_t value, unsigned char * buffer, size_t buffer_size) +{ + return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0); +} diff --git a/lib/libcbor/src/cbor/encoding.h b/lib/libcbor/src/cbor/encoding.h new file mode 100644 index 00000000000..8117582b6a1 --- /dev/null +++ b/lib/libcbor/src/cbor/encoding.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_ENCODING_H +#define LIBCBOR_ENCODING_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +* ============================================================================ +* Primitives encoding +* ============================================================================ +*/ + +size_t cbor_encode_uint8(uint8_t, unsigned char *, size_t); + +size_t cbor_encode_uint16(uint16_t, unsigned char *, size_t); + +size_t cbor_encode_uint32(uint32_t, unsigned char *, size_t); + +size_t cbor_encode_uint64(uint64_t, unsigned char *, size_t); + +size_t cbor_encode_uint(uint64_t, unsigned char *, size_t); + +size_t cbor_encode_negint8(uint8_t, unsigned char *, size_t); + +size_t cbor_encode_negint16(uint16_t, unsigned char *, size_t); + +size_t cbor_encode_negint32(uint32_t, unsigned char *, size_t); + +size_t cbor_encode_negint64(uint64_t, unsigned char *, size_t); + +size_t cbor_encode_negint(uint64_t, unsigned char *, size_t); + +size_t cbor_encode_bytestring_start(size_t, unsigned char *, size_t); + +size_t cbor_encode_indef_bytestring_start(unsigned char *, size_t); + +size_t cbor_encode_string_start(size_t, unsigned char *, size_t); + +size_t cbor_encode_indef_string_start(unsigned char *, size_t); + +size_t cbor_encode_array_start(size_t, unsigned char *, size_t); + +size_t cbor_encode_indef_array_start(unsigned char *, size_t); + +size_t cbor_encode_map_start(size_t, unsigned char *, size_t); + +size_t cbor_encode_indef_map_start(unsigned char *, size_t); + +size_t cbor_encode_tag(uint64_t, unsigned char *, size_t); + +size_t cbor_encode_bool(bool, unsigned char *, size_t); + +size_t cbor_encode_null(unsigned char *, size_t); + +size_t cbor_encode_undef(unsigned char *, size_t); + +/** Encodes a half-precision float + * + * Since there is no native representation or semantics for half floats + * in the language, we use single-precision floats, as every value that + * can be expressed as a half-float can also be expressed as a float. + * + * This however means that not all floats passed to this function can be + * unambiguously encoded. The behavior is as follows: + * - Infinity, NaN are preserved + * - Zero is preserved + * - Denormalized numbers keep their sign bit and 10 most significant bit of the significand + * - All other numbers + * - If the logical value of the exponent is < -24, the output is zero + * - If the logical value of the exponent is between -23 and -14, the output + * is cut off to represent the 'magnitude' of the input, by which we + * mean (-1)^{signbit} x 1.0e{exponent}. The value in the significand is lost. + * - In all other cases, the sign bit, the exponent, and 10 most significant bits + * of the significand are kept + * + * @param value + * @param buffer Target buffer + * @param buffer_size Available space in the buffer + * @return number of bytes written + */ +size_t cbor_encode_half(float, unsigned char *, size_t); + +size_t cbor_encode_single(float, unsigned char *, size_t); + +size_t cbor_encode_double(double, unsigned char *, size_t); + +size_t cbor_encode_break(unsigned char *, size_t); + +size_t cbor_encode_ctrl(uint8_t, unsigned char *, size_t); + +#ifdef __cplusplus +} +#endif + + +#endif //LIBCBOR_ENCODING_H diff --git a/lib/libcbor/src/cbor/floats_ctrls.c b/lib/libcbor/src/cbor/floats_ctrls.c new file mode 100644 index 00000000000..92bc1347ffc --- /dev/null +++ b/lib/libcbor/src/cbor/floats_ctrls.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "floats_ctrls.h" +#include "assert.h" +#include <math.h> + +cbor_float_width cbor_float_get_width(const cbor_item_t *item) +{ + assert(cbor_isa_float_ctrl(item)); + return item->metadata.float_ctrl_metadata.width; +} + +uint8_t cbor_ctrl_value(const cbor_item_t *item) +{ + assert(cbor_isa_float_ctrl(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_0); + return item->metadata.float_ctrl_metadata.ctrl; +} + +bool cbor_float_ctrl_is_ctrl(const cbor_item_t *item) +{ + assert(cbor_isa_float_ctrl(item)); + return cbor_float_get_width(item) == CBOR_FLOAT_0; +} + +float cbor_float_get_float2(const cbor_item_t *item) +{ + assert(cbor_is_float(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_16); + return *(float *) item->data; +} + +float cbor_float_get_float4(const cbor_item_t *item) +{ + assert(cbor_is_float(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_32); + return *(float *) item->data; +} + +double cbor_float_get_float8(const cbor_item_t *item) +{ + assert(cbor_is_float(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_64); + return *(double *) item->data; +} + +double cbor_float_get_float(const cbor_item_t * item) +{ + assert(cbor_is_float(item)); + switch(cbor_float_get_width(item)) { + case CBOR_FLOAT_0: return NAN; + case CBOR_FLOAT_16: return cbor_float_get_float2(item); + case CBOR_FLOAT_32: return cbor_float_get_float4(item); + case CBOR_FLOAT_64: return cbor_float_get_float8(item); + } + return NAN; /* Compiler complaints */ +} + +void cbor_set_float2(cbor_item_t *item, float value) +{ + assert(cbor_is_float(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_16); + *((float *) item->data) = value; +} + +void cbor_set_float4(cbor_item_t *item, float value) +{ + assert(cbor_is_float(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_32); + *((float *) item->data) = value; +} + +void cbor_set_float8(cbor_item_t *item, double value) +{ + assert(cbor_is_float(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_64); + *((double *) item->data) = value; +} + +void cbor_set_ctrl(cbor_item_t *item, uint8_t value) +{ + assert(cbor_isa_float_ctrl(item)); + assert(cbor_float_get_width(item) == CBOR_FLOAT_0); + item->metadata.float_ctrl_metadata.ctrl = value; +} + +bool cbor_ctrl_is_bool(const cbor_item_t *item) +{ + assert(cbor_is_bool(item)); + return item->metadata.float_ctrl_metadata.ctrl == CBOR_CTRL_TRUE; +} + +cbor_item_t *cbor_new_ctrl() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + *item = (cbor_item_t) { + .type = CBOR_TYPE_FLOAT_CTRL, + .data = NULL, + .refcount = 1, + .metadata = {.float_ctrl_metadata = {.width = CBOR_FLOAT_0, .ctrl = CBOR_CTRL_NONE}} + }; + return item; +} + +cbor_item_t *cbor_new_float2() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4); + *item = (cbor_item_t) { + .type = CBOR_TYPE_FLOAT_CTRL, + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.float_ctrl_metadata = {.width = CBOR_FLOAT_16}} + }; + return item; +} + +cbor_item_t *cbor_new_float4() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4); + *item = (cbor_item_t) { + .type = CBOR_TYPE_FLOAT_CTRL, + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.float_ctrl_metadata = {.width = CBOR_FLOAT_32}} + }; + return item; +} + +cbor_item_t *cbor_new_float8() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8); + *item = (cbor_item_t) { + .type = CBOR_TYPE_FLOAT_CTRL, + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.float_ctrl_metadata = {.width = CBOR_FLOAT_64}} + }; + return item; +} + +cbor_item_t *cbor_new_null() +{ + cbor_item_t *item = cbor_new_ctrl(); + cbor_set_ctrl(item, CBOR_CTRL_NULL); + return item; +} + +cbor_item_t *cbor_new_undef() +{ + cbor_item_t *item = cbor_new_ctrl(); + cbor_set_ctrl(item, CBOR_CTRL_UNDEF); + return item; +} + +cbor_item_t *cbor_build_bool(bool value) +{ + return cbor_build_ctrl(value ? CBOR_CTRL_TRUE : CBOR_CTRL_FALSE); +} + +cbor_item_t *cbor_build_float2(float value) +{ + cbor_item_t *item = cbor_new_float2(); + cbor_set_float2(item, value); + return item; +} + +cbor_item_t *cbor_build_float4(float value) +{ + cbor_item_t *item = cbor_new_float4(); + cbor_set_float4(item, value); + return item; +} + +cbor_item_t *cbor_build_float8(double value) +{ + cbor_item_t *item = cbor_new_float8(); + cbor_set_float8(item, value); + return item; +} + +cbor_item_t *cbor_build_ctrl(uint8_t value) +{ + cbor_item_t *item = cbor_new_ctrl(); + cbor_set_ctrl(item, value); + return item; +} diff --git a/lib/libcbor/src/cbor/floats_ctrls.h b/lib/libcbor/src/cbor/floats_ctrls.h new file mode 100644 index 00000000000..a5cdc40e90b --- /dev/null +++ b/lib/libcbor/src/cbor/floats_ctrls.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_FLOATS_CTRLS_H +#define LIBCBOR_FLOATS_CTRLS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* Float manipulation +* ============================================================================ +*/ + +/** Is this a ctrl value? + * + * @param item[borrow] A float or ctrl item + * @return Is this a ctrl value? + */ +bool cbor_float_ctrl_is_ctrl(const cbor_item_t * item); + +/** Get the float width + * + * @param item[borrow] A float or ctrl item + * @return The width. + */ +cbor_float_width cbor_float_get_width(const cbor_item_t * item); + +/** Get a half precision float + * + * The item must have the corresponding width + * + * @param[borrow] A half precision float + * @return half precision value + */ +float cbor_float_get_float2(const cbor_item_t * item); + +/** Get a single precision float + * + * The item must have the corresponding width + * + * @param[borrow] A signle precision float + * @return single precision value + */ +float cbor_float_get_float4(const cbor_item_t * item); + +/** Get a double precision float + * + * The item must have the corresponding width + * + * @param[borrow] A double precision float + * @return double precision value + */ +double cbor_float_get_float8(const cbor_item_t * item); + +/** Get the float value represented as double + * + * Can be used regardless of the width. + * + * @param[borrow] Any float + * @return double precision value + */ +double cbor_float_get_float(const cbor_item_t * item); + +/** Constructs a new ctrl item + * + * The width cannot be changed once the item is created + * + * @return **new** 1B ctrl + */ +cbor_item_t * cbor_new_ctrl(); + +/** Constructs a new float item + * + * The width cannot be changed once the item is created + * + * @return **new** 2B float + */ +cbor_item_t * cbor_new_float2(); + +/** Constructs a new float item + * + * The width cannot be changed once the item is created + * + * @return **new** 4B float + */ +cbor_item_t * cbor_new_float4(); + +/** Constructs a new float item + * + * The width cannot be changed once the item is created + * + * @return **new** 8B float + */ +cbor_item_t * cbor_new_float8(); + +/** Constructs new null ctrl item + * + * @return **new** null ctrl item + */ +cbor_item_t * cbor_new_null(); + +/** Constructs new under ctrl item + * + * @return **new** under ctrl item + */ +cbor_item_t * cbor_new_undef(); + +/** Constructs new boolean ctrl item + * + * @param value The value to use + * @return **new** boolen ctrl item + */ +cbor_item_t * cbor_build_bool(bool value); + +/** Assign a control value + * + * \rst + * .. warning:: It is possible to produce an invalid CBOR value by assigning a invalid value using this mechanism. Please consult the standard before use. + * \endrst + * + * @param item[borrow] A ctrl item + * @param value The simple value to assign. Please consult the standard for allowed values + */ +void cbor_set_ctrl(cbor_item_t * item, uint8_t value); + +/** Assigns a float value + * + * @param item[borrow] A half precision float + * @param value The value to assign + */ +void cbor_set_float2(cbor_item_t * item, float value); + +/** Assigns a float value + * + * @param item[borrow] A single precision float + * @param value The value to assign + */ +void cbor_set_float4(cbor_item_t * item, float value); + +/** Assigns a float value + * + * @param item[borrow] A double precision float + * @param value The value to assign + */ +void cbor_set_float8(cbor_item_t * item, double value); + +/** Reads the control value + * + * @param item[borrow] A ctrl item + * @return the simple value + */ +uint8_t cbor_ctrl_value(const cbor_item_t * item); + +/** Is this ctrl item a boolean? + * + * @param item[borrow] A ctrl item + * @return Is this ctrl item a boolean? + */ +bool cbor_ctrl_is_bool(const cbor_item_t * item); + +/** Constructs a new float + * + * @param value the value to use + * @return **new** float + */ +cbor_item_t *cbor_build_float2(float value); + +/** Constructs a new float + * + * @param value the value to use + * @return **new** float + */ +cbor_item_t *cbor_build_float4(float value); + +/** Constructs a new float + * + * @param value the value to use + * @return **new** float + */ +cbor_item_t *cbor_build_float8(double value); + +/** Constructs a ctrl item + * + * @param value the value to use + * @return **new** ctrl item + */ +cbor_item_t *cbor_build_ctrl(uint8_t value); + + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_FLOATS_CTRLS_H diff --git a/lib/libcbor/src/cbor/internal/builder_callbacks.c b/lib/libcbor/src/cbor/internal/builder_callbacks.c new file mode 100644 index 00000000000..7f28d28433f --- /dev/null +++ b/lib/libcbor/src/cbor/internal/builder_callbacks.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "builder_callbacks.h" +#include "unicode.h" +#include <string.h> +#include "../arrays.h" +#include "../bytestrings.h" +#include "../floats_ctrls.h" +#include "../ints.h" +#include "../maps.h" +#include "../strings.h" +#include "../tags.h" + +void _cbor_builder_append(cbor_item_t *item, struct _cbor_decoder_context *ctx) +{ + if (ctx->stack->size == 0) { + /* Top level item */ + ctx->root = item; + } else { + /* Part of a bigger structure */ + switch (ctx->stack->top->item->type) { + case CBOR_TYPE_ARRAY: { + if (cbor_array_is_definite(ctx->stack->top->item)) { + assert(ctx->stack->top->subitems > 0); + cbor_array_push(ctx->stack->top->item, item); + ctx->stack->top->subitems--; + if (ctx->stack->top->subitems == 0) { + cbor_item_t *item = ctx->stack->top->item; + _cbor_stack_pop(ctx->stack); + _cbor_builder_append(item, ctx); + } + cbor_decref(&item); + } else { + /* Indefinite array, don't bother with subitems */ + cbor_array_push(ctx->stack->top->item, item); + cbor_decref(&item); + } + break; + } + case CBOR_TYPE_MAP: { + /* We use 0 and 1 subitems to distinguish between keys and values in indefinite items */ + if (ctx->stack->top->subitems % 2) { + /* Odd record, this is a value */ + _cbor_map_add_value(ctx->stack->top->item, cbor_move(item)); + } else { + /* Even record, this is a key */ + _cbor_map_add_key(ctx->stack->top->item, cbor_move(item)); + } + if (cbor_map_is_definite(ctx->stack->top->item)) { + ctx->stack->top->subitems--; + if (ctx->stack->top->subitems == 0) { + cbor_item_t *item = ctx->stack->top->item; + _cbor_stack_pop(ctx->stack); + _cbor_builder_append(item, ctx); + } + } else { + ctx->stack->top->subitems ^= 1; /* Flip the indicator for indefinite items */ + } + break; + } + case CBOR_TYPE_TAG: { + assert(ctx->stack->top->subitems == 1); + cbor_tag_set_item(ctx->stack->top->item, item); + cbor_decref(&item); /* Give up on our reference */ + cbor_item_t *item = ctx->stack->top->item; + _cbor_stack_pop(ctx->stack); + _cbor_builder_append(item, ctx); + break; + } + default: { + cbor_decref(&item); + ctx->syntax_error = true; + } + } + } +} + + +#define CHECK_RES do { if (res == NULL) { ctx->creation_failed = true; return; } } 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; + 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; + 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; + 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; + 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; + 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(); + 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; + 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; + 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, size_t length) +{ + struct _cbor_decoder_context *ctx = context; + unsigned char *new_handle = _CBOR_MALLOC(length); + if (new_handle == NULL) { + ctx->creation_failed = true; + return; + } + + memcpy(new_handle, data, length); + cbor_item_t *res = cbor_new_definite_bytestring(); + + if (res == NULL) { + _CBOR_FREE(new_handle); + ctx->creation_failed = true; + return; + } + + cbor_bytestring_set_handle(res, new_handle, length); + + if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item)) { + if (cbor_bytestring_is_indefinite(ctx->stack->top->item)) { + cbor_bytestring_add_chunk(ctx->stack->top->item, cbor_move(res)); + } else { + cbor_decref(&res); + ctx->syntax_error = true; + } + } else { + _cbor_builder_append(res, 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; + _cbor_stack_push(ctx->stack, res, 0); +} + + +void cbor_builder_string_callback(void *context, cbor_data data, size_t length) +{ + struct _cbor_decoder_context *ctx = context; + struct _cbor_unicode_status unicode_status; + + size_t codepoint_count = _cbor_unicode_codepoint_count(data, length, &unicode_status); + + if (unicode_status.status == _CBOR_UNICODE_BADCP) { + ctx->syntax_error = true; + return; + } + + unsigned char *new_handle = _CBOR_MALLOC(length); + + if (new_handle == NULL) { + ctx->creation_failed = true; + return; + } + + memcpy(new_handle, data, length); + cbor_item_t *res = cbor_new_definite_string(); + cbor_string_set_handle(res, new_handle, length); + res->metadata.string_metadata.codepoint_count = codepoint_count; + + /* Careful here: order matters */ + if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item)) { + if (cbor_string_is_indefinite(ctx->stack->top->item)) { + cbor_string_add_chunk(ctx->stack->top->item, cbor_move(res)); + } else { + cbor_decref(&res); + ctx->syntax_error = true; + } + } else { + _cbor_builder_append(res, 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; + _cbor_stack_push(ctx->stack, res, 0); +} + +void cbor_builder_array_start_callback(void *context, size_t size) +{ + struct _cbor_decoder_context *ctx = context; + cbor_item_t *res = cbor_new_definite_array(size); + CHECK_RES; + if (size > 0) { + _cbor_stack_push(ctx->stack, 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; + _cbor_stack_push(ctx->stack, 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; + _cbor_stack_push(ctx->stack, res, 0); +} + +void cbor_builder_map_start_callback(void *context, size_t size) +{ + struct _cbor_decoder_context *ctx = context; + cbor_item_t *res = cbor_new_definite_map(size); + CHECK_RES; + if (size > 0) { + _cbor_stack_push(ctx->stack, res, size * 2); + } else { + _cbor_builder_append(res, ctx); + } +} + +void cbor_builder_indef_break_callback(void *context) +{ + struct _cbor_decoder_context *ctx = context; + if (ctx->stack->size == 0) { + // TODO complain + } else { + cbor_item_t *item = ctx->stack->top->item; + _cbor_stack_pop(ctx->stack); + _cbor_builder_append(item, ctx); + } +} + +void cbor_builder_float2_callback(void *context, float value) +{ + struct _cbor_decoder_context *ctx = context; + cbor_item_t *res = cbor_new_float2(); + 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; + 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; + 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; + _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; + _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; + _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; + _cbor_stack_push(ctx->stack, res, 1); +} diff --git a/lib/libcbor/src/cbor/internal/builder_callbacks.h b/lib/libcbor/src/cbor/internal/builder_callbacks.h new file mode 100644 index 00000000000..b16294f16af --- /dev/null +++ b/lib/libcbor/src/cbor/internal/builder_callbacks.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_BUILDER_CALLBACKS_H +#define LIBCBOR_BUILDER_CALLBACKS_H + +#include "cbor/common.h" +#include "../callbacks.h" +#include "stack.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** High-level decoding context */ +struct _cbor_decoder_context { + /** Callback creating the last item has failed */ + bool creation_failed; + /** Stack expectation mismatch */ + bool syntax_error; + cbor_item_t *root; + struct _cbor_stack *stack; +}; + +void cbor_builder_uint8_callback(void *, uint8_t); + +void cbor_builder_uint16_callback(void *, uint16_t); + +void cbor_builder_uint32_callback(void *, uint32_t); + +void cbor_builder_uint64_callback(void *, uint64_t); + +void cbor_builder_negint8_callback(void *, uint8_t); + +void cbor_builder_negint16_callback(void *, uint16_t); + +void cbor_builder_negint32_callback(void *, uint32_t); + +void cbor_builder_negint64_callback(void *, uint64_t); + +void cbor_builder_string_callback(void *, cbor_data, size_t); + +void cbor_builder_string_start_callback(void *); + +void cbor_builder_byte_string_callback(void *, cbor_data, size_t); + +void cbor_builder_byte_string_start_callback(void *); + +void cbor_builder_array_start_callback(void *, size_t); + +void cbor_builder_indef_array_start_callback(void *); + +void cbor_builder_map_start_callback(void *, size_t); + +void cbor_builder_indef_map_start_callback(void *); + +void cbor_builder_tag_callback(void *, uint64_t); + +void cbor_builder_float2_callback(void *, float); + +void cbor_builder_float4_callback(void *, float); + +void cbor_builder_float8_callback(void *, double); + +void cbor_builder_null_callback(void *); + +void cbor_builder_undefined_callback(void *); + +void cbor_builder_boolean_callback(void *, bool); + +void cbor_builder_indef_break_callback(void *); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_BUILDER_CALLBACKS_H diff --git a/lib/libcbor/src/cbor/internal/encoders.c b/lib/libcbor/src/cbor/internal/encoders.c new file mode 100644 index 00000000000..478b3885cb1 --- /dev/null +++ b/lib/libcbor/src/cbor/internal/encoders.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "encoders.h" + +#if HAVE_ENDIAN_H +#include <endian.h> +#endif + +size_t _cbor_encode_uint8(uint8_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset) +{ + if (value <= 23) { + if (buffer_size >= 1) { + buffer[0] = value + offset; + return 1; + } + } else { + if (buffer_size >= 2) { + buffer[0] = 0x18 + offset; + buffer[1] = value; + return 2; + } + } + return 0; +} + +size_t _cbor_encode_uint16(uint16_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset) +{ + if (buffer_size >= 3) { + buffer[0] = 0x19 + offset; + +#ifdef HAVE_ENDIAN_H + *(uint16_t *) &buffer[1] = htobe16(value); +#else + #ifdef IS_BIG_ENDIAN + *(uint16_t *) &buffer[1] = value; + #else + buffer[1] = value >> 8; + buffer[2] = value; + #endif +#endif + + return 3; + } else + return 0; +} + +size_t _cbor_encode_uint32(uint32_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset) +{ + if (buffer_size >= 5) { + buffer[0] = 0x1A + offset; + +#ifdef HAVE_ENDIAN_H + *(uint32_t *) &buffer[1] = htobe32(value); +#else + #ifdef IS_BIG_ENDIAN + *(uint32_t *) &buffer[1] = value; + #else + buffer[1] = value >> 24; + buffer[2] = value >> 16; + buffer[3] = value >> 8; + buffer[4] = value; + #endif +#endif + + return 5; + } else + return 0; +} + +size_t _cbor_encode_uint64(uint64_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset) +{ + if (buffer_size >= 9) { + buffer[0] = 0x1B + offset; + +#ifdef HAVE_ENDIAN_H + *(uint64_t *) &buffer[1] = htobe64(value); +#else + #ifdef IS_BIG_ENDIAN + *(uint64_t *) &buffer[1] = value; + #else + buffer[1] = value >> 56; + buffer[2] = value >> 48; + buffer[3] = value >> 40; + buffer[4] = value >> 32; + buffer[5] = value >> 24; + buffer[6] = value >> 16; + buffer[7] = value >> 8; + buffer[8] = value; + #endif +#endif + + return 9; + } else + return 0; +} + +size_t _cbor_encode_uint(uint64_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset) +{ + if (value <= UINT16_MAX) if (value <= UINT8_MAX) + return _cbor_encode_uint8((uint8_t) value, buffer, buffer_size, offset); + else + return _cbor_encode_uint16((uint16_t) value, buffer, buffer_size, offset); + else if (value <= UINT32_MAX) + return _cbor_encode_uint32((uint32_t) value, buffer, buffer_size, offset); + else + return _cbor_encode_uint64((uint64_t) value, buffer, buffer_size, offset); +} diff --git a/lib/libcbor/src/cbor/internal/encoders.h b/lib/libcbor/src/cbor/internal/encoders.h new file mode 100644 index 00000000000..5629e60905a --- /dev/null +++ b/lib/libcbor/src/cbor/internal/encoders.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_ENCODERS_H +#define LIBCBOR_ENCODERS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +size_t _cbor_encode_uint8(uint8_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset); + +size_t _cbor_encode_uint16(uint16_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset); + +size_t _cbor_encode_uint32(uint32_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset); + +size_t _cbor_encode_uint64(uint64_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset); + +size_t _cbor_encode_uint(uint64_t value, unsigned char *buffer, size_t buffer_size, uint8_t offset); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_ENCODERS_H diff --git a/lib/libcbor/src/cbor/internal/loaders.c b/lib/libcbor/src/cbor/internal/loaders.c new file mode 100644 index 00000000000..184691ca65a --- /dev/null +++ b/lib/libcbor/src/cbor/internal/loaders.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "loaders.h" +#include <math.h> + +#ifdef HAVE_ENDIAN_H +#include <endian.h> +#endif + +uint8_t _cbor_load_uint8(cbor_data source) +{ + return (uint8_t) *source; +} + +uint16_t _cbor_load_uint16(const unsigned char *source) +{ +#ifdef HAVE_ENDIAN_H + return be16toh(*(uint16_t *) source); +#else + #ifdef IS_BIG_ENDIAN + return *(uint16_t *) source; + #else + return ((uint16_t) *(source + 0) << 8) + + (uint8_t) *(source + 1); + #endif +#endif +} + +uint32_t _cbor_load_uint32(const unsigned char *source) +{ +#ifdef HAVE_ENDIAN_H + return be32toh(*(uint32_t *) source); +#else + #ifdef IS_BIG_ENDIAN + return *(uint32_t *) source; + #else + return ((uint32_t) *(source + 0) << 0x18) + + ((uint32_t) *(source + 1) << 0x10) + + ((uint16_t) *(source + 2) << 0x08) + + (uint8_t) *(source + 3); + #endif +#endif +} + +uint64_t _cbor_load_uint64(const unsigned char *source) +{ +#ifdef HAVE_ENDIAN_H + return be64toh(*(uint64_t *) source); +#else + #ifdef IS_BIG_ENDIAN + return *(uint64_t *) source; + #else + return ((uint64_t) *(source + 0) << 0x38) + + ((uint64_t) *(source + 1) << 0x30) + + ((uint64_t) *(source + 2) << 0x28) + + ((uint64_t) *(source + 3) << 0x20) + + ((uint32_t) *(source + 4) << 0x18) + + ((uint32_t) *(source + 5) << 0x10) + + ((uint16_t) *(source + 6) << 0x08) + + (uint8_t) *(source + 7); + #endif +#endif +} + +/* As per http://tools.ietf.org/html/rfc7049#appendix-D */ +float _cbor_decode_half(unsigned char *halfp) +{ + int half = (halfp[0] << 8) + halfp[1]; + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val; + if (exp == 0) val = ldexp(mant, -24); + else if (exp != 31) val = ldexp(mant + 1024, exp - 25); + else val = mant == 0 ? INFINITY : NAN; + return (float) (half & 0x8000 ? -val : val); +} + +double _cbor_load_half(cbor_data source) +{ + /* Discard const */ + return _cbor_decode_half((unsigned char *) source); +} + +float _cbor_load_float(cbor_data source) +{ + union _cbor_float_helper helper = {.as_uint = _cbor_load_uint32(source)}; + return helper.as_float; +} + +double _cbor_load_double(cbor_data source) +{ + union _cbor_double_helper helper = {.as_uint = _cbor_load_uint64(source)}; + return helper.as_double; +} diff --git a/lib/libcbor/src/cbor/internal/loaders.h b/lib/libcbor/src/cbor/internal/loaders.h new file mode 100644 index 00000000000..cd5c1b5a45c --- /dev/null +++ b/lib/libcbor/src/cbor/internal/loaders.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_LOADERS_H +#define LIBCBOR_LOADERS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Read the given uint from the given location, no questions asked */ +uint8_t _cbor_load_uint8(const unsigned char *source); + +uint16_t _cbor_load_uint16(const unsigned char *source); + +uint32_t _cbor_load_uint32(const unsigned char *source); + +uint64_t _cbor_load_uint64(const unsigned char *source); + +double _cbor_load_half(cbor_data source); + +float _cbor_load_float(cbor_data source); + +double _cbor_load_double(cbor_data source); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_LOADERS_H diff --git a/lib/libcbor/src/cbor/internal/memory_utils.c b/lib/libcbor/src/cbor/internal/memory_utils.c new file mode 100644 index 00000000000..4d1024c4236 --- /dev/null +++ b/lib/libcbor/src/cbor/internal/memory_utils.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "memory_utils.h" +#include "cbor/common.h" + +// TODO: Consider builtins (https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html) + +/** Highest on bit position */ +size_t _cbor_highest_bit(size_t number) +{ + size_t bit = 0; + while (number != 0) { + bit++; + number >>= 1; + } + + return bit; +} + +bool _cbor_safe_to_multiply(size_t a, size_t b) +{ + return _cbor_highest_bit(a) + _cbor_highest_bit(b) <= sizeof(size_t) * 8; +} + +void * _cbor_alloc_multiple(size_t item_size, size_t item_count) +{ + if (_cbor_safe_to_multiply(item_size, item_count)) { + return _CBOR_MALLOC(item_size * item_count); + } else { + return NULL; + } +} + +void * _cbor_realloc_multiple(void * pointer, size_t item_size, size_t item_count) +{ + if (_cbor_safe_to_multiply(item_size, item_count)) { + return _CBOR_REALLOC(pointer, item_size * item_count); + } else { + return NULL; + } +} diff --git a/lib/libcbor/src/cbor/internal/memory_utils.h b/lib/libcbor/src/cbor/internal/memory_utils.h new file mode 100644 index 00000000000..cec008d7578 --- /dev/null +++ b/lib/libcbor/src/cbor/internal/memory_utils.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_MEMORY_UTILS_H +#define LIBCBOR_MEMORY_UTILS_H + +#include <string.h> +#include <stdbool.h> + +/** Can a and b be multiplied without overflowing size_t? */ +bool _cbor_safe_to_multiply(size_t a, size_t b); + +/** Overflow-proof contiguous array allocation + * + * @param item_size + * @param item_count + * @return Region of item_size * item_count bytes, or NULL if the total size overflows size_t or the underlying allocator failed + */ +void * _cbor_alloc_multiple(size_t item_size, size_t item_count); + + +/** Overflow-proof contiguous array reallocation + * + * This implements the OpenBSD `reallocarray` functionality. + * + * @param pointer + * @param item_size + * @param item_count + * @return Realloc'd of item_size * item_count bytes, or NULL if the total size overflows size_t or the underlying allocator failed + */ +void * _cbor_realloc_multiple(void * pointer, size_t item_size, size_t item_count); + +#endif //LIBCBOR_MEMORY_UTILS_H diff --git a/lib/libcbor/src/cbor/internal/stack.c b/lib/libcbor/src/cbor/internal/stack.c new file mode 100644 index 00000000000..65e15fe9379 --- /dev/null +++ b/lib/libcbor/src/cbor/internal/stack.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "stack.h" + +struct _cbor_stack _cbor_stack_init() +{ + return (struct _cbor_stack) {.top = NULL, .size = 0}; +} + +void _cbor_stack_pop(struct _cbor_stack *stack) +{ + struct _cbor_stack_record *top = stack->top; + stack->top = stack->top->lower; + _CBOR_FREE(top); + stack->size--; +} + +struct _cbor_stack_record *_cbor_stack_push(struct _cbor_stack *stack, cbor_item_t *item, size_t subitems) +{ + struct _cbor_stack_record *new_top = _CBOR_MALLOC(sizeof(struct _cbor_stack_record)); + if (new_top == NULL) + return NULL; + + *new_top = (struct _cbor_stack_record) {stack->top, item, subitems}; + stack->top = new_top; + stack->size++; + return new_top; +} diff --git a/lib/libcbor/src/cbor/internal/stack.h b/lib/libcbor/src/cbor/internal/stack.h new file mode 100644 index 00000000000..53b97090ade --- /dev/null +++ b/lib/libcbor/src/cbor/internal/stack.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_STACK_H +#define LIBCBOR_STACK_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Simple stack record for the parser */ +struct _cbor_stack_record { + struct _cbor_stack_record *lower; + cbor_item_t *item; + size_t subitems; +}; + +/** Stack handle - contents and size */ +struct _cbor_stack { + struct _cbor_stack_record *top; + size_t size; +}; + +struct _cbor_stack _cbor_stack_init(); + +void _cbor_stack_pop(struct _cbor_stack *); + +struct _cbor_stack_record *_cbor_stack_push(struct _cbor_stack *, cbor_item_t *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_STACK_H diff --git a/lib/libcbor/src/cbor/internal/unicode.c b/lib/libcbor/src/cbor/internal/unicode.c new file mode 100644 index 00000000000..23403095561 --- /dev/null +++ b/lib/libcbor/src/cbor/internal/unicode.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "unicode.h" + +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 1 + +static const uint8_t utf8d[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00..1f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20..3f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40..5f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60..7f */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, /* 80..9f */ + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* a0..bf */ + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* c0..df */ + 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, /* e0..ef */ + 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, /* f0..ff */ + 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, /* s0..s0 */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, /* s1..s2 */ + 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, /* s3..s4 */ + 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, /* s5..s6 */ + 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* s7..s8 */ +}; + +/* Copyright of this function: (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> */ +/* See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. */ +uint32_t _cbor_unicode_decode(uint32_t* state, uint32_t* codep, uint32_t byte) { + uint32_t type = utf8d[byte]; + + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); + + *state = utf8d[256 + *state * 16 + type]; + return *state; +} + +size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length, struct _cbor_unicode_status * status) +{ + *status = (struct _cbor_unicode_status) { .location = 0, .status = _CBOR_UNICODE_OK }; + uint32_t codepoint, state = UTF8_ACCEPT, res; + size_t pos = 0, count = 0; + + for (; pos < source_length; pos++) + { + res = _cbor_unicode_decode(&state, &codepoint, source[pos]); + + if (res == UTF8_ACCEPT) { + count++; + } else if (res == UTF8_REJECT) { + goto error; + } + } + + /* Unfinished multibyte codepoint */ + if (state != UTF8_ACCEPT) + goto error; + + return count; + + error: + *status = (struct _cbor_unicode_status) { .location = pos, .status = _CBOR_UNICODE_BADCP }; + return -1; +} diff --git a/lib/libcbor/src/cbor/internal/unicode.h b/lib/libcbor/src/cbor/internal/unicode.h new file mode 100644 index 00000000000..9d80bafcab2 --- /dev/null +++ b/lib/libcbor/src/cbor/internal/unicode.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_UNICODE_H +#define LIBCBOR_UNICODE_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum _cbor_unicode_status_error { + _CBOR_UNICODE_OK, + _CBOR_UNICODE_BADCP +}; + +/** Signals unicode validation error and possibly its location */ +struct _cbor_unicode_status { + enum _cbor_unicode_status_error status; + size_t location; +}; + +size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length, struct _cbor_unicode_status * status); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_UNICODE_H diff --git a/lib/libcbor/src/cbor/ints.c b/lib/libcbor/src/cbor/ints.c new file mode 100644 index 00000000000..26f08cd3453 --- /dev/null +++ b/lib/libcbor/src/cbor/ints.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "ints.h" + +cbor_int_width cbor_int_get_width(const cbor_item_t *item) +{ + assert(cbor_is_int(item)); + return item->metadata.int_metadata.width; +} + +uint8_t cbor_get_uint8(const cbor_item_t *item) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_8); + return *item->data; +} + +uint16_t cbor_get_uint16(const cbor_item_t *item) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_16); + return *(uint16_t *) item->data; +} + +uint32_t cbor_get_uint32(const cbor_item_t *item) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_32); + return *(uint32_t *) item->data; +} + +uint64_t cbor_get_uint64(const cbor_item_t *item) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_64); + return *(uint64_t *) item->data; +} + +uint64_t cbor_get_int(const cbor_item_t * item) +{ + assert(cbor_is_int(item)); + switch(cbor_int_get_width(item)) { + case CBOR_INT_8: return cbor_get_uint8(item); + case CBOR_INT_16: return cbor_get_uint16(item); + case CBOR_INT_32: return cbor_get_uint32(item); + case CBOR_INT_64: return cbor_get_uint64(item); + } + return 0xDEADBEEF; /* Compiler complaints */ +} + +void cbor_set_uint8(cbor_item_t *item, uint8_t value) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_8); + *item->data = value; +} + +void cbor_set_uint16(cbor_item_t *item, uint16_t value) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_16); + *(uint16_t *) item->data = value; +} + + +void cbor_set_uint32(cbor_item_t *item, uint32_t value) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_32); + *(uint32_t *) item->data = value; +} + +void cbor_set_uint64(cbor_item_t *item, uint64_t value) +{ + assert(cbor_is_int(item)); + assert(cbor_int_get_width(item) == CBOR_INT_64); + *(uint64_t *) item->data = value; +} + +void cbor_mark_uint(cbor_item_t *item) +{ + assert(cbor_is_int(item)); + item->type = CBOR_TYPE_UINT; +} + +void cbor_mark_negint(cbor_item_t *item) +{ + assert(cbor_is_int(item)); + item->type = CBOR_TYPE_NEGINT; +} + +cbor_item_t *cbor_new_int8() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 1); + *item = (cbor_item_t) { + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.int_metadata = {.width = CBOR_INT_8}}, + .type = CBOR_TYPE_UINT + }; + return item; +} + +cbor_item_t *cbor_new_int16() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 2); + *item = (cbor_item_t) { + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.int_metadata = {.width = CBOR_INT_16}}, + .type = CBOR_TYPE_UINT + }; + return item; +} + +cbor_item_t *cbor_new_int32() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4); + *item = (cbor_item_t) { + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.int_metadata = {.width = CBOR_INT_32}}, + .type = CBOR_TYPE_UINT + }; + return item; +} + +cbor_item_t *cbor_new_int64() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8); + *item = (cbor_item_t) { + .data = (unsigned char *) item + sizeof(cbor_item_t), + .refcount = 1, + .metadata = {.int_metadata = {.width = CBOR_INT_64}}, + .type = CBOR_TYPE_UINT + }; + return item; +} + +cbor_item_t *cbor_build_uint8(uint8_t value) +{ + cbor_item_t *item = cbor_new_int8(); + cbor_set_uint8(item, value); + cbor_mark_uint(item); + return item; +} + +cbor_item_t *cbor_build_uint16(uint16_t value) +{ + cbor_item_t *item = cbor_new_int16(); + cbor_set_uint16(item, value); + cbor_mark_uint(item); + return item; +} + +cbor_item_t *cbor_build_uint32(uint32_t value) +{ + cbor_item_t *item = cbor_new_int32(); + cbor_set_uint32(item, value); + cbor_mark_uint(item); + return item; +} + +cbor_item_t *cbor_build_uint64(uint64_t value) +{ + cbor_item_t *item = cbor_new_int64(); + cbor_set_uint64(item, value); + cbor_mark_uint(item); + return item; +} + +cbor_item_t *cbor_build_negint8(uint8_t value) +{ + cbor_item_t *item = cbor_new_int8(); + cbor_set_uint8(item, value); + cbor_mark_negint(item); + return item; +} + +cbor_item_t *cbor_build_negint16(uint16_t value) +{ + cbor_item_t *item = cbor_new_int16(); + cbor_set_uint16(item, value); + cbor_mark_negint(item); + return item; +} + +cbor_item_t *cbor_build_negint32(uint32_t value) +{ + cbor_item_t *item = cbor_new_int32(); + cbor_set_uint32(item, value); + cbor_mark_negint(item); + return item; +} + +cbor_item_t *cbor_build_negint64(uint64_t value) +{ + cbor_item_t *item = cbor_new_int64(); + cbor_set_uint64(item, value); + cbor_mark_negint(item); + return item; +} diff --git a/lib/libcbor/src/cbor/ints.h b/lib/libcbor/src/cbor/ints.h new file mode 100644 index 00000000000..31f9d056a4b --- /dev/null +++ b/lib/libcbor/src/cbor/ints.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_INTS_H +#define LIBCBOR_INTS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* Integer (uints and negints) manipulation +* ============================================================================ +*/ + +/** Extracts the integer value + * + * @param item[borrow] positive or negative integer + * @return the value + */ +uint8_t cbor_get_uint8(const cbor_item_t *item); + +/** Extracts the integer value + * + * @param item[borrow] positive or negative integer + * @return the value + */ +uint16_t cbor_get_uint16(const cbor_item_t *item); + +/** Extracts the integer value + * + * @param item[borrow] positive or negative integer + * @return the value + */ +uint32_t cbor_get_uint32(const cbor_item_t *item); + +/** Extracts the integer value + * + * @param item[borrow] positive or negative integer + * @return the value + */ +uint64_t cbor_get_uint64(const cbor_item_t *item); + +/** Extracts the integer value + * + * @param item[borrow] positive or negative integer + * @return the value, extended to `uint64_t` + */ +uint64_t cbor_get_int(const cbor_item_t *item); + +/** Assigns the integer value + * + * @param item[borrow] positive or negative integer item + * @param value the value to assign. For negative integer, the logical value is `-value - 1` + */ +void cbor_set_uint8(cbor_item_t *item, uint8_t value); + +/** Assigns the integer value + * + * @param item[borrow] positive or negative integer item + * @param value the value to assign. For negative integer, the logical value is `-value - 1` + */ +void cbor_set_uint16(cbor_item_t *item, uint16_t value); + +/** Assigns the integer value + * + * @param item[borrow] positive or negative integer item + * @param value the value to assign. For negative integer, the logical value is `-value - 1` + */ +void cbor_set_uint32(cbor_item_t *item, uint32_t value); + +/** Assigns the integer value + * + * @param item[borrow] positive or negative integer item + * @param value the value to assign. For negative integer, the logical value is `-value - 1` + */ +void cbor_set_uint64(cbor_item_t *item, uint64_t value); + +/** Queries the integer width + * + * @param item[borrow] positive or negative integer item + * @return the width + */ +cbor_int_width cbor_int_get_width(const cbor_item_t *item); + +/** Marks the integer item as a positive integer + * + * The data value is not changed + * + * @param item[borrow] positive or negative integer item + */ +void cbor_mark_uint(cbor_item_t *item); + +/** Marks the integer item as a negative integer + * + * The data value is not changed + * + * @param item[borrow] positive or negative integer item + */ +void cbor_mark_negint(cbor_item_t *item); + +/** Allocates new integer with 1B width + * + * The width cannot be changed once allocated + * + * @return **new** positive integer. The value is not initialized. + */ +cbor_item_t *cbor_new_int8(); + +/** Allocates new integer with 2B width + * + * The width cannot be changed once allocated + * + * @return **new** positive integer. The value is not initialized. + */ +cbor_item_t *cbor_new_int16(); + +/** Allocates new integer with 4B width + * + * The width cannot be changed once allocated + * + * @return **new** positive integer. The value is not initialized. + */ +cbor_item_t *cbor_new_int32(); + +/** Allocates new integer with 8B width + * + * The width cannot be changed once allocated + * + * @return **new** positive integer. The value is not initialized. + */ +cbor_item_t *cbor_new_int64(); + +/** Constructs a new positive integer + * + * @param value the value to use + * @return **new** positive integer + */ +cbor_item_t *cbor_build_uint8(uint8_t value); + +/** Constructs a new positive integer + * + * @param value the value to use + * @return **new** positive integer + */ +cbor_item_t *cbor_build_uint16(uint16_t value); + +/** Constructs a new positive integer + * + * @param value the value to use + * @return **new** positive integer + */ +cbor_item_t *cbor_build_uint32(uint32_t value); + +/** Constructs a new positive integer + * + * @param value the value to use + * @return **new** positive integer + */ +cbor_item_t *cbor_build_uint64(uint64_t value); + +/** Constructs a new negative integer + * + * @param value the value to use + * @return **new** negative integer + */ +cbor_item_t *cbor_build_negint8(uint8_t value); + +/** Constructs a new negative integer + * + * @param value the value to use + * @return **new** negative integer + */ +cbor_item_t *cbor_build_negint16(uint16_t value); + +/** Constructs a new negative integer + * + * @param value the value to use + * @return **new** negative integer + */ +cbor_item_t *cbor_build_negint32(uint32_t value); + +/** Constructs a new negative integer + * + * @param value the value to use + * @return **new** negative integer + */ +cbor_item_t *cbor_build_negint64(uint64_t value); + + + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_INTS_H diff --git a/lib/libcbor/src/cbor/maps.c b/lib/libcbor/src/cbor/maps.c new file mode 100644 index 00000000000..8a70d0cad64 --- /dev/null +++ b/lib/libcbor/src/cbor/maps.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "maps.h" +#include "internal/memory_utils.h" + +size_t cbor_map_size(const cbor_item_t *item) +{ + assert(cbor_isa_map(item)); + return item->metadata.map_metadata.end_ptr; +} + +size_t cbor_map_allocated(const cbor_item_t *item) +{ + assert(cbor_isa_map(item)); + return item->metadata.map_metadata.allocated; +} + +cbor_item_t *cbor_new_definite_map(size_t size) +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + if (item == NULL) { + return NULL; + } + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_MAP, + .metadata = {.map_metadata = { + .allocated = size, + .type = _CBOR_METADATA_DEFINITE, + .end_ptr = 0 + }}, + .data = _cbor_alloc_multiple(sizeof(struct cbor_pair), size) + }; + if (item->data == NULL) { + _CBOR_FREE(item); + return NULL; + } + return item; +} + +cbor_item_t *cbor_new_indefinite_map() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + if (item == NULL) + return NULL; + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_MAP, + .metadata = {.map_metadata = { + .allocated = 0, + .type = _CBOR_METADATA_INDEFINITE, + .end_ptr = 0 + }}, + .data = NULL + }; + + return item; +} + + +bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) +{ + assert(cbor_isa_map(item)); + struct _cbor_map_metadata *metadata = (struct _cbor_map_metadata *) &item->metadata; + if (cbor_map_is_definite(item)) { + struct cbor_pair *data = cbor_map_handle(item); + if (metadata->end_ptr >= metadata->allocated) { + /* Don't realloc definite preallocated map */ + return false; + } + + data[metadata->end_ptr].key = key; + data[metadata->end_ptr++].value = NULL; + } else { + if (metadata->end_ptr >= metadata->allocated) { + /* Exponential realloc */ + // Check for overflows first + if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) { + return false; + } + + size_t new_allocation = metadata->allocated == 0 ? 1 : CBOR_BUFFER_GROWTH * metadata->allocated; + + unsigned char * new_data = _cbor_realloc_multiple(item->data, sizeof(struct cbor_pair), new_allocation); + + if (new_data == NULL) { + return false; + } + + item->data = new_data; + metadata->allocated = new_allocation; + } + struct cbor_pair *data = cbor_map_handle(item); + data[metadata->end_ptr].key = key; + data[metadata->end_ptr++].value = NULL; + } + cbor_incref(key); + return true; +} + +bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) +{ + assert(cbor_isa_map(item)); + cbor_incref(value); + cbor_map_handle(item)[ + /* Move one back since we are assuming _add_key (which increased the ptr) + * was the previous operation on this object */ + item->metadata.map_metadata.end_ptr - 1 + ].value = value; + return true; +} + +bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) +{ + assert(cbor_isa_map(item)); + if (!_cbor_map_add_key(item, pair.key)) + return false; + return _cbor_map_add_value(item, pair.value); +} + +bool cbor_map_is_definite(const cbor_item_t *item) +{ + assert(cbor_isa_map(item)); + return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE; +} + +bool cbor_map_is_indefinite(const cbor_item_t *item) +{ + return !cbor_map_is_definite(item); +} + +struct cbor_pair *cbor_map_handle(const cbor_item_t *item) +{ + assert(cbor_isa_map(item)); + return (struct cbor_pair *) item->data; +} diff --git a/lib/libcbor/src/cbor/maps.h b/lib/libcbor/src/cbor/maps.h new file mode 100644 index 00000000000..cd433b310f3 --- /dev/null +++ b/lib/libcbor/src/cbor/maps.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_MAPS_H +#define LIBCBOR_MAPS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* Map manipulation +* ============================================================================ +*/ + +/** Get the number of pairs + * + * @param item[borrow] A map + * @return The number of pairs + */ +size_t cbor_map_size(const cbor_item_t *item); + +/** Get the size of the allocated storage + * + * @param item[borrow] A map + * @return Allocated storage size (as the number of #cbor_pair items) + */ +size_t cbor_map_allocated(const cbor_item_t *item); + +/** Create a new definite map + * + * @param size The number of slots to preallocate + * @return **new** definite map. `NULL` on malloc failure. + */ +cbor_item_t *cbor_new_definite_map(size_t size); + +/** Create a new indefinite map + * + * @param size The number of slots to preallocate + * @return **new** definite map. `NULL` on malloc failure. + */ +cbor_item_t *cbor_new_indefinite_map(); + +/** Add a pair to the map + * + * For definite maps, items can only be added to the preallocated space. For indefinite + * maps, the storage will be expanded as needed + * + * @param item[borrow] A map + * @param pair[incref] The key-value pair to add (incref is member-wise) + * @return `true` on success, `false` if either reallocation failed or the preallcoated storage is full + */ +bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair); + +/** Add a key to the map + * + * Sets the value to `NULL`. Internal API. + * + * @param item[borrow] A map + * @param key[incref] The key + * @return `true` on success, `false` if either reallocation failed or the preallcoated storage is full + */ +bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key); + +/** Add a value to the map + * + * Assumes that #_cbor_map_add_key has been called. Internal API. + * + * @param item[borrow] A map + * @param key[incref] The value + * @return `true` on success, `false` if either reallocation failed or the preallcoated storage is full + */ +bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value); + +/** Is this map definite? + * + * @param item[borrow] A map + * @return Is this map definite? + */ +bool cbor_map_is_definite(const cbor_item_t *item); + +/** Is this map indefinite? + * + * @param item[borrow] A map + * @return Is this map indefinite? + */ +bool cbor_map_is_indefinite(const cbor_item_t *item); + +/** Get the pairs storage + * + * @param item[borrow] A map + * @return Array of #cbor_map_size pairs. Manipulation is possible as long as references remain valid. + */ +struct cbor_pair *cbor_map_handle(const cbor_item_t *item); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_MAPS_H diff --git a/lib/libcbor/src/cbor/serialization.c b/lib/libcbor/src/cbor/serialization.c new file mode 100644 index 00000000000..52f2bbe8b34 --- /dev/null +++ b/lib/libcbor/src/cbor/serialization.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "serialization.h" +#include "encoding.h" +#include "cbor/arrays.h" +#include "cbor/bytestrings.h" +#include "cbor/floats_ctrls.h" +#include "cbor/ints.h" +#include "cbor/maps.h" +#include "cbor/strings.h" +#include "cbor/tags.h" +#include "internal/memory_utils.h" +#include <string.h> + +size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + switch (cbor_typeof(item)) { + case CBOR_TYPE_UINT: + return cbor_serialize_uint(item, buffer, buffer_size); + case CBOR_TYPE_NEGINT: + return cbor_serialize_negint(item, buffer, buffer_size); + case CBOR_TYPE_BYTESTRING: + return cbor_serialize_bytestring(item, buffer, buffer_size); + case CBOR_TYPE_STRING: + return cbor_serialize_string(item, buffer, buffer_size); + case CBOR_TYPE_ARRAY: + return cbor_serialize_array(item, buffer, buffer_size); + case CBOR_TYPE_MAP: + return cbor_serialize_map(item, buffer, buffer_size); + case CBOR_TYPE_TAG: + return cbor_serialize_tag(item, buffer, buffer_size); + case CBOR_TYPE_FLOAT_CTRL: + return cbor_serialize_float_ctrl(item, buffer, buffer_size); + default: + return 0; + } +} + +size_t cbor_serialize_alloc(const cbor_item_t * item, + unsigned char ** buffer, + size_t * buffer_size) +{ + size_t bfr_size = 32; + unsigned char * bfr = _CBOR_MALLOC(bfr_size), * tmp_bfr; + if (bfr == NULL) { + return 0; + } + + size_t written; + + /* This is waaay too optimistic - figure out something smarter (eventually) */ + while ((written = cbor_serialize(item, bfr, bfr_size)) == 0) { + if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, bfr_size)) { + _CBOR_FREE(bfr); + return 0; + } + + tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2); + + if (tmp_bfr == NULL) { + _CBOR_FREE(bfr); + return 0; + } + bfr = tmp_bfr; + } + *buffer = bfr; + *buffer_size = bfr_size; + return written; +} + +size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_uint(item)); + switch (cbor_int_get_width(item)) { + case CBOR_INT_8: + return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size); + case CBOR_INT_16: + return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size); + case CBOR_INT_32: + return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size); + case CBOR_INT_64: + return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size); + default: + return 0; + } +} + +size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_negint(item)); + switch (cbor_int_get_width(item)) { + case CBOR_INT_8: + return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size); + case CBOR_INT_16: + return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size); + case CBOR_INT_32: + return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size); + case CBOR_INT_64: + return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size); + default: + return 0; + } +} + +size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_bytestring(item)); + if (cbor_bytestring_is_definite(item)) { + size_t length = cbor_bytestring_length(item); + size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size); + if (written && (buffer_size - written >= length)) { + memcpy(buffer + written, cbor_bytestring_handle(item), length); + return written + length; + } else + return 0; + } else { + assert(cbor_bytestring_is_indefinite(item)); + size_t chunk_count = cbor_bytestring_chunk_count(item); + size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size); + + if (written == 0) + return 0; + + cbor_item_t **chunks = cbor_bytestring_chunks_handle(item); + for (size_t i = 0; i < chunk_count; i++) { + size_t chunk_written = cbor_serialize_bytestring(chunks[i], buffer + written, buffer_size - written); + if (chunk_written == 0) + return 0; + else + written += chunk_written; + } + if (cbor_encode_break(buffer + written, buffer_size - written) > 0) + return written + 1; + else + return 0; + } +} + +size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_string(item)); + if (cbor_string_is_definite(item)) { + size_t length = cbor_string_length(item); + size_t written = cbor_encode_string_start(length, buffer, buffer_size); + if (written && (buffer_size - written >= length)) { + memcpy(buffer + written, cbor_string_handle(item), length); + return written + length; + } else + return 0; + } else { + assert(cbor_string_is_indefinite(item)); + size_t chunk_count = cbor_string_chunk_count(item); + size_t written = cbor_encode_indef_string_start(buffer, buffer_size); + + if (written == 0) + return 0; + + cbor_item_t **chunks = cbor_string_chunks_handle(item); + for (size_t i = 0; i < chunk_count; i++) { + size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written, buffer_size - written); + if (chunk_written == 0) + return 0; + else + written += chunk_written; + } + if (cbor_encode_break(buffer + written, buffer_size - written) > 0) + return written + 1; + else + return 0; + } +} + +size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_array(item)); + size_t size = cbor_array_size(item), + written = 0; + cbor_item_t **handle = cbor_array_handle(item); + if (cbor_array_is_definite(item)) { + written = cbor_encode_array_start(size, buffer, buffer_size); + } else { + assert(cbor_array_is_indefinite(item)); + written = cbor_encode_indef_array_start(buffer, buffer_size); + } + if (written == 0) + return 0; + + size_t item_written; + for (size_t i = 0; i < size; i++) { + item_written = cbor_serialize(*(handle++), buffer + written, buffer_size - written); + if (item_written == 0) + return 0; + else + written += item_written; + } + + if (cbor_array_is_definite(item)) { + return written; + } else { + assert(cbor_array_is_indefinite(item)); + item_written = cbor_encode_break(buffer + written, buffer_size - written); + if (item_written == 0) + return 0; + else + return written + 1; + } +} + +size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_map(item)); + size_t size = cbor_map_size(item), + written = 0; + struct cbor_pair * handle = cbor_map_handle(item); + + if (cbor_map_is_definite(item)) { + written = cbor_encode_map_start(size, buffer, buffer_size); + } else { + assert(cbor_map_is_indefinite(item)); + written = cbor_encode_indef_map_start(buffer, buffer_size); + } + if (written == 0) + return 0; + + size_t item_written; + for (size_t i = 0; i < size; i++) { + item_written = cbor_serialize(handle->key, buffer + written, buffer_size - written); + if (item_written == 0) + return 0; + else + written += item_written; + item_written = cbor_serialize((handle++)->value, buffer + written, buffer_size - written); + if (item_written == 0) + return 0; + else + written += item_written; + } + + if (cbor_map_is_definite(item)) { + return written; + } else { + assert(cbor_map_is_indefinite(item)); + item_written = cbor_encode_break(buffer + written, buffer_size - written); + if (item_written == 0) + return 0; + else + return written + 1; + } +} + +size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_tag(item)); + size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size); + if (written == 0) + return 0; + + size_t item_written = cbor_serialize(cbor_tag_item(item), buffer + written, buffer_size - written); + if (item_written == 0) + return 0; + else + return written + item_written; +} + +size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer, size_t buffer_size) +{ + assert(cbor_isa_float_ctrl(item)); + switch (cbor_float_get_width(item)) { + case CBOR_FLOAT_0: + /* CTRL - special treatment */ + return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size); + case CBOR_FLOAT_16: + return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size); + case CBOR_FLOAT_32: + return cbor_encode_single(cbor_float_get_float4(item), buffer, buffer_size); + case CBOR_FLOAT_64: + return cbor_encode_double(cbor_float_get_float8(item), buffer, buffer_size); + } + + /* Should never happen - make the compiler happy */ + return 0; +} diff --git a/lib/libcbor/src/cbor/serialization.h b/lib/libcbor/src/cbor/serialization.h new file mode 100644 index 00000000000..75b0f02437e --- /dev/null +++ b/lib/libcbor/src/cbor/serialization.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_SERIALIZATION_H +#define LIBCBOR_SERIALIZATION_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +* ============================================================================ +* High level encoding +* ============================================================================ +*/ + +/** Serialize the given item + * + * @param item[borrow] A data item + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize(const cbor_item_t * item, cbor_mutable_data buffer, size_t buffer_size); + +/** Serialize the given item, allocating buffers as needed + * + * \rst + * .. warning:: It is your responsibility to free the buffer using an appropriate ``free`` implementation. + * \endrst + * + * @param item[borrow] A data item + * @param buffer[out] Buffer containing the result + * @param buffer_size[out] Size of the \p buffer + * @return Length of the result. 0 on failure, in which case \p buffer is ``NULL``. + */ +size_t cbor_serialize_alloc(const cbor_item_t * item, cbor_mutable_data * buffer, size_t * buffer_size); + +/** Serialize an uint + * + * @param item[borrow] A uint + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_uint(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize a negint + * + * @param item[borrow] A neging + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_negint(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize a bytestring + * + * @param item[borrow] A bytestring + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_bytestring(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize a string + * + * @param item[borrow] A string + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_string(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize an array + * + * @param item[borrow] An array + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_array(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize a map + * + * @param item[borrow] A map + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_map(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize a tag + * + * @param item[borrow] A tag + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_tag(const cbor_item_t *, cbor_mutable_data, size_t); + +/** Serialize a + * + * @param item[borrow] A float or ctrl + * @param buffer Buffer to serialize to + * @param buffer_size Size of the \p buffer + * @return Length of the result. 0 on failure. + */ +size_t cbor_serialize_float_ctrl(const cbor_item_t *, cbor_mutable_data, size_t); + +#ifdef __cplusplus +} +#endif + + +#endif //LIBCBOR_SERIALIZATION_H diff --git a/lib/libcbor/src/cbor/streaming.c b/lib/libcbor/src/cbor/streaming.c new file mode 100644 index 00000000000..b6398c5b541 --- /dev/null +++ b/lib/libcbor/src/cbor/streaming.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "streaming.h" +#include "internal/loaders.h" + +bool static _cbor_claim_bytes(size_t required, + size_t provided, struct cbor_decoder_result *result) +{ + if (required > (provided - result->read)) { + /* We need to keep all the metadata if parsing is to be resumed */ + result->read = 0; + result->status = CBOR_DECODER_NEDATA; + return false; + } else { + result->read += required; + return true; + } +} + + +struct cbor_decoder_result cbor_stream_decode(cbor_data source, size_t source_size, + const struct cbor_callbacks *callbacks, + void *context) +{ + /* If we have no data, we cannot read even the MTB */ + if (source_size < 1) { + return (struct cbor_decoder_result) {0, CBOR_DECODER_EBUFFER}; + } + + /* If we have a byte, assume it's the MTB */ + struct cbor_decoder_result result = {1, CBOR_DECODER_FINISHED}; + + switch (*source) { + case 0x00: /* Fallthrough */ + case 0x01: /* Fallthrough */ + case 0x02: /* Fallthrough */ + case 0x03: /* Fallthrough */ + case 0x04: /* Fallthrough */ + case 0x05: /* Fallthrough */ + case 0x06: /* Fallthrough */ + case 0x07: /* Fallthrough */ + case 0x08: /* Fallthrough */ + case 0x09: /* Fallthrough */ + case 0x0A: /* Fallthrough */ + case 0x0B: /* Fallthrough */ + case 0x0C: /* Fallthrough */ + case 0x0D: /* Fallthrough */ + case 0x0E: /* Fallthrough */ + case 0x0F: /* Fallthrough */ + case 0x10: /* Fallthrough */ + case 0x11: /* Fallthrough */ + case 0x12: /* Fallthrough */ + case 0x13: /* Fallthrough */ + case 0x14: /* Fallthrough */ + case 0x15: /* Fallthrough */ + case 0x16: /* Fallthrough */ + case 0x17: + /* Embedded one byte unsigned integer */ + { + callbacks->uint8(context, _cbor_load_uint8(source)); + return result; + } + case 0x18: + /* One byte unsigned integer */ + { + if (_cbor_claim_bytes(1, source_size, &result)) { + callbacks->uint8(context, _cbor_load_uint8(source + 1)); + } + return result; + } + case 0x19: + /* Two bytes unsigned integer */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + callbacks->uint16(context, _cbor_load_uint16(source + 1)); + } + return result; + } + case 0x1A: + /* Four bytes unsigned integer */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + callbacks->uint32(context, _cbor_load_uint32(source + 1)); + } + return result; + } + case 0x1B: + /* Eight bytes unsigned integer */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + callbacks->uint64(context, _cbor_load_uint64(source + 1)); + } + return result; + } + case 0x1C: /* Fallthrough */ + case 0x1D: /* Fallthrough */ + case 0x1E: /* Fallthrough */ + case 0x1F: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0x20: /* Fallthrough */ + case 0x21: /* Fallthrough */ + case 0x22: /* Fallthrough */ + case 0x23: /* Fallthrough */ + case 0x24: /* Fallthrough */ + case 0x25: /* Fallthrough */ + case 0x26: /* Fallthrough */ + case 0x27: /* Fallthrough */ + case 0x28: /* Fallthrough */ + case 0x29: /* Fallthrough */ + case 0x2A: /* Fallthrough */ + case 0x2B: /* Fallthrough */ + case 0x2C: /* Fallthrough */ + case 0x2D: /* Fallthrough */ + case 0x2E: /* Fallthrough */ + case 0x2F: /* Fallthrough */ + case 0x30: /* Fallthrough */ + case 0x31: /* Fallthrough */ + case 0x32: /* Fallthrough */ + case 0x33: /* Fallthrough */ + case 0x34: /* Fallthrough */ + case 0x35: /* Fallthrough */ + case 0x36: /* Fallthrough */ + case 0x37: + /* Embedded one byte negative integer */ + { + callbacks->negint8(context, _cbor_load_uint8(source) - 0x20); /* 0x20 offset */ + return result; + } + case 0x38: + /* One byte negative integer */ + { + if (_cbor_claim_bytes(1, source_size, &result)) { + callbacks->negint8(context, _cbor_load_uint8(source + 1)); + } + return result; + } + case 0x39: + /* Two bytes negative integer */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + callbacks->negint16(context, _cbor_load_uint16(source + 1)); + } + return result; + } + case 0x3A: + /* Four bytes negative integer */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + callbacks->negint32(context, _cbor_load_uint32(source + 1)); + } + return result; + } + case 0x3B: + /* Eight bytes negative integer */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + callbacks->negint64(context, _cbor_load_uint64(source + 1)); + } + return result; + } + case 0x3C: /* Fallthrough */ + case 0x3D: /* Fallthrough */ + case 0x3E: /* Fallthrough */ + case 0x3F: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0x40: /* Fallthrough */ + case 0x41: /* Fallthrough */ + case 0x42: /* Fallthrough */ + case 0x43: /* Fallthrough */ + case 0x44: /* Fallthrough */ + case 0x45: /* Fallthrough */ + case 0x46: /* Fallthrough */ + case 0x47: /* Fallthrough */ + case 0x48: /* Fallthrough */ + case 0x49: /* Fallthrough */ + case 0x4A: /* Fallthrough */ + case 0x4B: /* Fallthrough */ + case 0x4C: /* Fallthrough */ + case 0x4D: /* Fallthrough */ + case 0x4E: /* Fallthrough */ + case 0x4F: /* Fallthrough */ + case 0x50: /* Fallthrough */ + case 0x51: /* Fallthrough */ + case 0x52: /* Fallthrough */ + case 0x53: /* Fallthrough */ + case 0x54: /* Fallthrough */ + case 0x55: /* Fallthrough */ + case 0x56: /* Fallthrough */ + case 0x57: + /* Embedded length byte string */ + { + size_t length = (size_t) _cbor_load_uint8(source) - 0x40; /* 0x40 offset */ + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->byte_string(context, source + 1, length); + } + return result; + } + case 0x58: + /* One byte length byte string */ + // TODO template this? + { + if (_cbor_claim_bytes(1, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint8(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->byte_string(context, source + 1 + 1, length); + } + } + return result; + } + case 0x59: + /* Two bytes length byte string */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint16(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->byte_string(context, source + 1 + 2, length); + } + } + return result; + } + case 0x5A: + /* Four bytes length byte string */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint32(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->byte_string(context, source + 1 + 4, length); + } + } + return result; + } + case 0x5B: + /* Eight bytes length byte string */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint64(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->byte_string(context, source + 1 + 8, length); + } + } + return result; + } + case 0x5C: /* Fallthrough */ + case 0x5D: /* Fallthrough */ + case 0x5E: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0x5F: + /* Indefinite byte string */ + { + callbacks->byte_string_start(context); + return result; + } + case 0x60: /* Fallthrough */ + case 0x61: /* Fallthrough */ + case 0x62: /* Fallthrough */ + case 0x63: /* Fallthrough */ + case 0x64: /* Fallthrough */ + case 0x65: /* Fallthrough */ + case 0x66: /* Fallthrough */ + case 0x67: /* Fallthrough */ + case 0x68: /* Fallthrough */ + case 0x69: /* Fallthrough */ + case 0x6A: /* Fallthrough */ + case 0x6B: /* Fallthrough */ + case 0x6C: /* Fallthrough */ + case 0x6D: /* Fallthrough */ + case 0x6E: /* Fallthrough */ + case 0x6F: /* Fallthrough */ + case 0x70: /* Fallthrough */ + case 0x71: /* Fallthrough */ + case 0x72: /* Fallthrough */ + case 0x73: /* Fallthrough */ + case 0x74: /* Fallthrough */ + case 0x75: /* Fallthrough */ + case 0x76: /* Fallthrough */ + case 0x77: + /* Embedded one byte length string */ + { + size_t length = (size_t) _cbor_load_uint8(source) - 0x60; /* 0x60 offset */ + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->string(context, source + 1, length); + } + return result; + } + case 0x78: + /* One byte length string */ + { + if (_cbor_claim_bytes(1, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint8(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->string(context, source + 1 + 1, length); + } + } + return result; + } + case 0x79: + /* Two bytes length string */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint16(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->string(context, source + 1 + 2, length); + } + } + return result; + } + case 0x7A: + /* Four bytes length string */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint32(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->string(context, source + 1 + 4, length); + } + } + return result; + } + case 0x7B: + /* Eight bytes length string */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + size_t length = (size_t) _cbor_load_uint64(source + 1); + if (_cbor_claim_bytes(length, source_size, &result)) { + callbacks->string(context, source + 1 + 8, length); + } + } + return result; + } + case 0x7C: /* Fallthrough */ + case 0x7D: /* Fallthrough */ + case 0x7E: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0x7F: + /* Indefinite length string */ + { + callbacks->string_start(context); + return result; + } + case 0x80: /* Fallthrough */ + case 0x81: /* Fallthrough */ + case 0x82: /* Fallthrough */ + case 0x83: /* Fallthrough */ + case 0x84: /* Fallthrough */ + case 0x85: /* Fallthrough */ + case 0x86: /* Fallthrough */ + case 0x87: /* Fallthrough */ + case 0x88: /* Fallthrough */ + case 0x89: /* Fallthrough */ + case 0x8A: /* Fallthrough */ + case 0x8B: /* Fallthrough */ + case 0x8C: /* Fallthrough */ + case 0x8D: /* Fallthrough */ + case 0x8E: /* Fallthrough */ + case 0x8F: /* Fallthrough */ + case 0x90: /* Fallthrough */ + case 0x91: /* Fallthrough */ + case 0x92: /* Fallthrough */ + case 0x93: /* Fallthrough */ + case 0x94: /* Fallthrough */ + case 0x95: /* Fallthrough */ + case 0x96: /* Fallthrough */ + case 0x97: + /* Embedded one byte length array */ + { + callbacks->array_start(context, (size_t) _cbor_load_uint8(source) - 0x80); /* 0x40 offset */ + return result; + } + case 0x98: + /* One byte length array */ + { + if (_cbor_claim_bytes(1, source_size, &result)) { + callbacks->array_start(context, (size_t) _cbor_load_uint8(source + 1)); + } + return result; + } + case 0x99: + /* Two bytes length string */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + callbacks->array_start(context, (size_t) _cbor_load_uint16(source + 1)); + } + return result; + } + case 0x9A: + /* Four bytes length string */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + callbacks->array_start(context, (size_t) _cbor_load_uint32(source + 1)); + } + return result; + } + case 0x9B: + /* Eight bytes length string */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + callbacks->array_start(context, (size_t) _cbor_load_uint64(source + 1)); + } + return result; + } + case 0x9C: /* Fallthrough */ + case 0x9D: /* Fallthrough */ + case 0x9E: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0x9F: + /* Indefinite length array */ + { + callbacks->indef_array_start(context); + return result; + } + case 0xA0: /* Fallthrough */ + case 0xA1: /* Fallthrough */ + case 0xA2: /* Fallthrough */ + case 0xA3: /* Fallthrough */ + case 0xA4: /* Fallthrough */ + case 0xA5: /* Fallthrough */ + case 0xA6: /* Fallthrough */ + case 0xA7: /* Fallthrough */ + case 0xA8: /* Fallthrough */ + case 0xA9: /* Fallthrough */ + case 0xAA: /* Fallthrough */ + case 0xAB: /* Fallthrough */ + case 0xAC: /* Fallthrough */ + case 0xAD: /* Fallthrough */ + case 0xAE: /* Fallthrough */ + case 0xAF: /* Fallthrough */ + case 0xB0: /* Fallthrough */ + case 0xB1: /* Fallthrough */ + case 0xB2: /* Fallthrough */ + case 0xB3: /* Fallthrough */ + case 0xB4: /* Fallthrough */ + case 0xB5: /* Fallthrough */ + case 0xB6: /* Fallthrough */ + case 0xB7: + /* Embedded one byte length map */ + { + callbacks->map_start(context, (size_t) _cbor_load_uint8(source) - 0xA0); /* 0xA0 offset */ + return result; + } + case 0xB8: + /* One byte length map */ + { + if (_cbor_claim_bytes(1, source_size, &result)) { + callbacks->map_start(context, (size_t) _cbor_load_uint8(source + 1)); + } + return result; + } + case 0xB9: + /* Two bytes length map */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + callbacks->map_start(context, (size_t) _cbor_load_uint16(source + 1)); + } + return result; + } + case 0xBA: + /* Four bytes length map */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + callbacks->map_start(context, (size_t) _cbor_load_uint32(source + 1)); + } + return result; + } + case 0xBB: + /* Eight bytes length map */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + callbacks->map_start(context, (size_t) _cbor_load_uint64(source + 1)); + } + return result; + } + case 0xBC: /* Fallthrough */ + case 0xBD: /* Fallthrough */ + case 0xBE: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0xBF: + /* Indefinite length map */ + { + callbacks->indef_map_start(context); + return result; + } + case 0xC0: + /* Text date/time - RFC 3339 tag, fallthrough */ + case 0xC1: + /* Epoch date tag, fallthrough */ + case 0xC2: + /* Positive bignum tag, fallthrough */ + case 0xC3: + /* Negative bignum tag, fallthrough */ + case 0xC4: + /* Fraction, fallthrough */ + case 0xC5: + /* Big float */ + { + callbacks->tag(context, _cbor_load_uint8(source) - 0xC0); /* 0xC0 offset */ + return result; + } + case 0xC6: /* Fallthrough */ + case 0xC7: /* Fallthrough */ + case 0xC8: /* Fallthrough */ + case 0xC9: /* Fallthrough */ + case 0xCA: /* Fallthrough */ + case 0xCB: /* Fallthrough */ + case 0xCC: /* Fallthrough */ + case 0xCD: /* Fallthrough */ + case 0xCE: /* Fallthrough */ + case 0xCF: /* Fallthrough */ + case 0xD0: /* Fallthrough */ + case 0xD1: /* Fallthrough */ + case 0xD2: /* Fallthrough */ + case 0xD3: /* Fallthrough */ + case 0xD4: /* Unassigned tag value */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0xD5: /* Expected b64url conversion tag - fallthrough */ + case 0xD6: /* Expected b64 conversion tag - fallthrough */ + case 0xD7: /* Expected b16 conversion tag */ + { + callbacks->tag(context, _cbor_load_uint8(source) - 0xC0); /* 0xC0 offset */ + return result; + } + case 0xD8: /* 1B tag */ + { + if (_cbor_claim_bytes(1, source_size, &result)) { + callbacks->tag(context, _cbor_load_uint8(source + 1)); + } + return result; + } + case 0xD9: /* 2B tag */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + callbacks->tag(context, _cbor_load_uint16(source + 1)); + } + return result; + } + case 0xDA: /* 4B tag */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + callbacks->tag(context, _cbor_load_uint32(source + 1)); + } + return result; + } + case 0xDB: /* 8B tag */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + callbacks->tag(context, _cbor_load_uint64(source + 1)); + } + return result; + } + case 0xDC: /* Fallthrough */ + case 0xDD: /* Fallthrough */ + case 0xDE: /* Fallthrough */ + case 0xDF: /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0xE0: /* Fallthrough */ + case 0xE1: /* Fallthrough */ + case 0xE2: /* Fallthrough */ + case 0xE3: /* Fallthrough */ + case 0xE4: /* Fallthrough */ + case 0xE5: /* Fallthrough */ + case 0xE6: /* Fallthrough */ + case 0xE7: /* Fallthrough */ + case 0xE8: /* Fallthrough */ + case 0xE9: /* Fallthrough */ + case 0xEA: /* Fallthrough */ + case 0xEB: /* Fallthrough */ + case 0xEC: /* Fallthrough */ + case 0xED: /* Fallthrough */ + case 0xEE: /* Fallthrough */ + case 0xEF: /* Fallthrough */ + case 0xF0: /* Fallthrough */ + case 0xF1: /* Fallthrough */ + case 0xF2: /* Fallthrough */ + case 0xF3: /* Simple value - unassigned */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0xF4: + /* False */ + { + callbacks->boolean(context, false); + return result; + } + case 0xF5: + /* True */ + { + callbacks->boolean(context, true); + return result; + } + case 0xF6: + /* Null */ + { + callbacks->null(context); + return result; + } + case 0xF7: + /* Undefined */ + { + callbacks->undefined(context); + return result; + } + case 0xF8: + /* 1B simple value, unassigned */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0xF9: + /* 2B float */ + { + if (_cbor_claim_bytes(2, source_size, &result)) { + callbacks->float2(context, _cbor_load_half(source + 1)); + } + return result; + } + case 0xFA: + /* 4B float */ + { + if (_cbor_claim_bytes(4, source_size, &result)) { + callbacks->float4(context, _cbor_load_float(source + 1)); + } + return result; + } + case 0xFB: + /* 8B float */ + { + if (_cbor_claim_bytes(8, source_size, &result)) { + callbacks->float8(context, _cbor_load_double(source + 1)); + } + return result; + } + case 0xFC: /* Fallthrough */ + case 0xFD: /* Fallthrough */ + case 0xFE: + /* Reserved */ + { + return (struct cbor_decoder_result) {0, CBOR_DECODER_ERROR}; + } + case 0xFF: + /* Break */ + { + callbacks->indef_break(context); + return result; + } + default: /* Never happens - this shuts up the compiler */ + { + return result; + } + } +} + + + + + + + + + + diff --git a/lib/libcbor/src/cbor/streaming.h b/lib/libcbor/src/cbor/streaming.h new file mode 100644 index 00000000000..b3e3c685b91 --- /dev/null +++ b/lib/libcbor/src/cbor/streaming.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_STREAMING_H +#define LIBCBOR_STREAMING_H + +#include "cbor/common.h" +#include "callbacks.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Stateless decoder + * + * Will try parsing the \p buffer and will invoke the appropriate callback on success. + * Decodes one item at a time. No memory allocations occur. + * + * @param buffer Input buffer + * @param buffer_size Length of the buffer + * @param callbacks The callback bundle + * @param context An arbitrary pointer to allow for maintaining context. + */ +struct cbor_decoder_result cbor_stream_decode(cbor_data buffer, + size_t buffer_size, + const struct cbor_callbacks * callbacks, + void * context); + + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_STREAMING_H diff --git a/lib/libcbor/src/cbor/strings.c b/lib/libcbor/src/cbor/strings.c new file mode 100644 index 00000000000..35589ac9cf7 --- /dev/null +++ b/lib/libcbor/src/cbor/strings.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <string.h> +#include "strings.h" +#include "internal/memory_utils.h" + +cbor_item_t *cbor_new_definite_string() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_STRING, + .metadata = {.string_metadata = {_CBOR_METADATA_DEFINITE, 0}} + }; + return item; +} + +cbor_item_t *cbor_new_indefinite_string() +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_STRING, + .metadata = {.string_metadata = {.type = _CBOR_METADATA_INDEFINITE, .length = 0}}, + .data = _CBOR_MALLOC(sizeof(struct cbor_indefinite_string_data)) + }; + *((struct cbor_indefinite_string_data *) item->data) = (struct cbor_indefinite_string_data) { + .chunk_count = 0, + .chunk_capacity = 0, + .chunks = NULL, + }; + return item; +} + +cbor_item_t *cbor_build_string(const char *val) +{ + cbor_item_t *item = cbor_new_definite_string(); + size_t len = strlen(val); + unsigned char * handle = _CBOR_MALLOC(len); + memcpy(handle, val, len); + cbor_string_set_handle(item, handle, len); + return item; +} + +cbor_item_t *cbor_build_stringn(const char *val, size_t length) +{ + cbor_item_t *item = cbor_new_definite_string(); + unsigned char * handle = _CBOR_MALLOC(length); + memcpy(handle, val, length); + cbor_string_set_handle(item, handle, length); + return item; +} + +void cbor_string_set_handle(cbor_item_t *item, cbor_mutable_data CBOR_RESTRICT_POINTER data, size_t length) +{ + assert(cbor_isa_string(item)); + assert(cbor_string_is_definite(item)); + item->data = data; + item->metadata.string_metadata.length = length; +} + +cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item) +{ + assert(cbor_isa_string(item)); + assert(cbor_string_is_indefinite(item)); + return ((struct cbor_indefinite_string_data *) item->data)->chunks; +} + +size_t cbor_string_chunk_count(const cbor_item_t *item) +{ + assert(cbor_isa_string(item)); + assert(cbor_string_is_indefinite(item)); + return ((struct cbor_indefinite_string_data *) item->data)->chunk_count; + +} + +bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk) +{ + assert(cbor_isa_string(item)); + assert(cbor_string_is_indefinite(item)); + struct cbor_indefinite_string_data *data = (struct cbor_indefinite_string_data *) item->data; + if (data->chunk_count == data->chunk_capacity) { + /* We need more space */ + if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) { + return false; + } + + data->chunk_capacity = data->chunk_capacity == 0 ? 1 : CBOR_BUFFER_GROWTH * (data->chunk_capacity); + cbor_item_t **new_chunks_data = _cbor_realloc_multiple(data->chunks, sizeof(cbor_item_t *), data->chunk_capacity); + + if (new_chunks_data == NULL) { + return false; + } + + data->chunks = new_chunks_data; + } + data->chunks[data->chunk_count++] = cbor_incref(chunk); + return true; +} + +size_t cbor_string_length(const cbor_item_t *item) +{ + assert(cbor_isa_string(item)); + return item->metadata.string_metadata.length; +} + +unsigned char *cbor_string_handle(const cbor_item_t *item) +{ + assert(cbor_isa_string(item)); + return item->data; +} + +size_t cbor_string_codepoint_count(const cbor_item_t *item) +{ + assert(cbor_isa_string(item)); + return item->metadata.string_metadata.codepoint_count; +} + +bool cbor_string_is_definite(const cbor_item_t *item) +{ + assert(cbor_isa_string(item)); + return item->metadata.string_metadata.type == _CBOR_METADATA_DEFINITE; +} + +bool cbor_string_is_indefinite(const cbor_item_t *item) +{ + return !cbor_string_is_definite(item); +} diff --git a/lib/libcbor/src/cbor/strings.h b/lib/libcbor/src/cbor/strings.h new file mode 100644 index 00000000000..2ec3de9cb20 --- /dev/null +++ b/lib/libcbor/src/cbor/strings.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_STRINGS_H +#define LIBCBOR_STRINGS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* String manipulation +* ============================================================================ +*/ + +/** Returns the length of the underlying string + * + * For definite strings only + * + * @param item[borrow] a definite string + * @return length of the string. Zero if no chunk has been attached yet + */ +size_t cbor_string_length(const cbor_item_t *item); + +/** The number of codepoints in this string + * + * Might differ from length if there are multibyte ones + * + * @param item[borrow] A string + * @return The number of codepoints in this string + */ +size_t cbor_string_codepoint_count(const cbor_item_t *item); + +/** Is the string definite? + * + * @param item[borrow] a string + * @return Is the string definite? + */ +bool cbor_string_is_definite(const cbor_item_t *item); + +/** Is the string indefinite? + * + * @param item[borrow] a string + * @return Is the string indefinite? + */ +bool cbor_string_is_indefinite(const cbor_item_t *item); + +/** Get the handle to the underlying string + * + * Definite items only. Modifying the data is allowed. In that case, the caller takes + * responsibility for the effect on items this item might be a part of + * + * @param item[borrow] A definite string + * @return The address of the underlying string. `NULL` if no data have been assigned yet. + */ +cbor_mutable_data cbor_string_handle(const cbor_item_t *item); + +/** Set the handle to the underlying string + * + * + * \rst + * .. warning:: Using a pointer to a stack allocated constant is a common mistake. Lifetime of the string will expire when it goes out of scope and the CBOR item will be left inconsistent. + * \endrst + * + * @param item[borrow] A definite string + * @param data The memory block. The caller gives up the ownership of the block. libcbor will deallocate it when appropriate using its free function + * @param length Length of the data block + */ +void cbor_string_set_handle(cbor_item_t *item, cbor_mutable_data CBOR_RESTRICT_POINTER data, size_t length); + +/** Get the handle to the array of chunks + * + * Manipulations with the memory block (e.g. sorting it) are allowed, but the validity and the number of chunks must be retained. + * + * @param item[borrow] A indefinite string + * @return array of #cbor_string_chunk_count definite strings + */ +cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item); + +/** Get the number of chunks this string consist of + * + * @param item[borrow] A indefinite string + * @return The chunk count. 0 for freshly created items. + */ +size_t cbor_string_chunk_count(const cbor_item_t *item); + +/** Appends a chunk to the string + * + * Indefinite strings only. + * + * May realloc the chunk storage. + * + * @param item[borrow] An indefinite string + * @param item[incref] A definite string + * @return true on success. false on realloc failure. In that case, the refcount of `chunk` is not increased and the `item` is left intact. + */ +bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk); + +/** Creates a new definite string + * + * The handle is initialized to `NULL` and length to 0 + * + * @return **new** definite string. `NULL` on malloc failure. + */ +cbor_item_t *cbor_new_definite_string(); + +/** Creates a new indefinite string + * + * The chunks array is initialized to `NULL` and chunkcount to 0 + * + * @return **new** indefinite string. `NULL` on malloc failure. + */ +cbor_item_t *cbor_new_indefinite_string(); + +/** Creates a new string and initializes it + * + * The `val` will be copied to a newly allocated block + * + * @param val A null-terminated UTF-8 string + * @return A **new** string with content `handle`. `NULL` on malloc failure. + */ +cbor_item_t *cbor_build_string(const char *val); + +/** Creates a new string and initializes it + * + * The `handle` will be copied to a newly allocated block + * + * @param val A UTF-8 string, at least \p length long (excluding the null byte) + * @return A **new** string with content `handle`. `NULL` on malloc failure. + */ +cbor_item_t *cbor_build_stringn(const char *val, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_STRINGS_H diff --git a/lib/libcbor/src/cbor/tags.c b/lib/libcbor/src/cbor/tags.c new file mode 100644 index 00000000000..09ec05610b0 --- /dev/null +++ b/lib/libcbor/src/cbor/tags.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "tags.h" + +cbor_item_t *cbor_new_tag(uint64_t value) +{ + cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); + *item = (cbor_item_t) { + .refcount = 1, + .type = CBOR_TYPE_TAG, + .metadata = {.tag_metadata = {.value = value, .tagged_item = NULL}}, + .data = NULL /* Never used */ + }; + return item; +} + +cbor_item_t *cbor_tag_item(const cbor_item_t *item) +{ + assert(cbor_isa_tag(item)); + return item->metadata.tag_metadata.tagged_item; +} + +uint64_t cbor_tag_value(const cbor_item_t *item) +{ + assert(cbor_isa_tag(item)); + return item->metadata.tag_metadata.value; +} + +void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item) +{ + assert(cbor_isa_tag(item)); + cbor_incref(tagged_item); + item->metadata.tag_metadata.tagged_item = tagged_item; +} + +cbor_item_t * cbor_build_tag(uint64_t value, cbor_item_t * item) { + cbor_item_t *res = cbor_new_tag(value); + cbor_tag_set_item(res, item); + return res; +} diff --git a/lib/libcbor/src/cbor/tags.h b/lib/libcbor/src/cbor/tags.h new file mode 100644 index 00000000000..f74cb636e3f --- /dev/null +++ b/lib/libcbor/src/cbor/tags.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com> + * + * libcbor is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIBCBOR_TAGS_H +#define LIBCBOR_TAGS_H + +#include "cbor/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* ============================================================================ +* Tag manipulation +* ============================================================================ +*/ + +/** Create a new tag + * + * @param value The tag value. Please consult the tag repository + * @return **new** tag. Item reference is `NULL`. + */ +cbor_item_t *cbor_new_tag(uint64_t value); + +/** Get the tagged item + * + * @param item[borrow] A tag + * @return **incref** the tagged item + */ +cbor_item_t *cbor_tag_item(const cbor_item_t *item); + +/** Get tag value + * + * @param item[borrow] A tag + * @return The tag value. Please consult the tag repository + */ +uint64_t cbor_tag_value(const cbor_item_t *item); + +/** Set the tagged item + * + * @param item[borrow] A tag + * @param tagged_item[incref] The item to tag + */ +void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item); + +/** Build a new tag + * + * @param item[incref] The tagee + * @param value Tag value + * @return **new** tag item + */ +cbor_item_t * cbor_build_tag(uint64_t value, cbor_item_t * item); + +#ifdef __cplusplus +} +#endif + +#endif //LIBCBOR_TAGS_H |