-# $OpenBSD: Makefile,v 1.3 2020/08/03 02:34:31 djm Exp $
+# $OpenBSD: Makefile,v 1.4 2022/12/31 03:35:21 djm Exp $
.PATH: ${.CURDIR}/src ${.CURDIR}/src/cbor ${.CURDIR}/src/cbor/internal
CFLAGS+= -I${.CURDIR}/src -DHAVE_ENDIAN_H -std=c99
+# We don't support custom allocators.
+CFLAGS+= -D_cbor_malloc=malloc -D_cbor_realloc=realloc -D_cbor_free=free
LIB= cbor
SRCS= cbor.c
HDRS+= cbor/configuration.h cbor/data.h cbor/encoding.h cbor/floats_ctrls.h
HDRS+= cbor/ints.h cbor/maps.h cbor/serialization.h cbor/streaming.h
HDRS+= cbor/strings.h cbor/tags.h
+# This file is generated by upstream's CMake rules.
+HDRS+= cbor/cbor_export.h
NOMAN=
## Contributions
-All bug reports and contributions are welcome. Please see https://github.com/PJK/libcbor for more info.
+Bug reports and contributions are welcome. Please see [CONTRIBUTING.md](https://github.com/PJK/libcbor/blob/master/CONTRIBUTING.md) for more info.
Kudos to all the [contributors](https://github.com/PJK/libcbor/graphs/contributors)!
-This is an import of https://github.com/pjk/libcbor v0.7.0
+This is an import of https://github.com/pjk/libcbor v0.10.0 with
+e308674c5d to fix https://github.com/PJK/libcbor/issues/259
Apart from README.md and LICENSE.md, only the src/ directory has been
imported.
+
+Note that the custom allocator feature (cbor_set_allocs()) has been
+disabled in this import and the allocation functions _cbor_malloc, etc.
+are #defined to the usual libc implementations.
-major=1
+major=2
minor=0
#include "cbor/common.h"
-_cbor_malloc_t _cbor_malloc = malloc;
-_cbor_realloc_t _cbor_realloc = realloc;
-_cbor_free_t _cbor_free = free;
+CBOR_EXPORT _cbor_malloc_t _cbor_malloc = malloc;
+CBOR_EXPORT _cbor_realloc_t _cbor_realloc = realloc;
+CBOR_EXPORT _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) {
result->error.code = CBOR_ERR_NOTENOUGHDATA;
goto error;
}
- case CBOR_DECODER_EBUFFER:
- /* Fallthrough */
case CBOR_DECODER_ERROR:
- /* Reserved/malformated item */
+ /* Reserved/malformed item */
{
result->error.code = CBOR_ERR_MALFORMATED;
goto error;
}
} while (stack.size > 0);
- /* Move the result before free */
- cbor_item_t *result_item = context.root;
- return result_item;
+ return context.root;
error:
result->error.position = result->read;
case CBOR_INT_64:
res = cbor_build_uint64(cbor_get_uint64(item));
break;
- default:
- return NULL;
}
if (negative) cbor_mark_negint(res);
}
static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
+ // cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return cbor_build_ctrl(cbor_ctrl_value(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) {
+ // cppcheck-suppress missingReturn
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return _cbor_copy_int(item, false);
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])));
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
+ cbor_item_t *chunk_copy =
+ cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
+ if (chunk_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
+ cbor_decref(&chunk_copy);
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_decref(&chunk_copy);
+ }
return res;
}
case CBOR_TYPE_STRING:
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])));
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
+ cbor_item_t *chunk_copy =
+ cbor_copy(cbor_string_chunks_handle(item)[i]);
+ if (chunk_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ if (!cbor_string_add_chunk(res, chunk_copy)) {
+ cbor_decref(&chunk_copy);
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_decref(&chunk_copy);
+ }
return res;
}
case CBOR_TYPE_ARRAY: {
cbor_item_t *res;
- if (cbor_array_is_definite(item))
+ if (cbor_array_is_definite(item)) {
res = cbor_new_definite_array(cbor_array_size(item));
- else
+ } else {
res = cbor_new_indefinite_array();
+ }
+ if (res == NULL) {
+ return NULL;
+ }
- 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)))));
+ for (size_t i = 0; i < cbor_array_size(item); i++) {
+ cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
+ if (entry_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ if (!cbor_array_push(res, entry_copy)) {
+ cbor_decref(&entry_copy);
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_decref(&entry_copy);
+ }
return res;
}
case CBOR_TYPE_MAP: {
cbor_item_t *res;
- if (cbor_map_is_definite(item))
+ if (cbor_map_is_definite(item)) {
res = cbor_new_definite_map(cbor_map_size(item));
- else
+ } else {
res = cbor_new_indefinite_map();
+ }
+ if (res == NULL) {
+ return NULL;
+ }
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))});
+ for (size_t i = 0; i < cbor_map_size(item); i++) {
+ cbor_item_t *key_copy = cbor_copy(it[i].key);
+ if (key_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_item_t *value_copy = cbor_copy(it[i].value);
+ if (value_copy == NULL) {
+ cbor_decref(&res);
+ cbor_decref(&key_copy);
+ return NULL;
+ }
+ if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
+ .value = value_copy})) {
+ cbor_decref(&res);
+ cbor_decref(&key_copy);
+ cbor_decref(&value_copy);
+ return NULL;
+ }
+ cbor_decref(&key_copy);
+ cbor_decref(&value_copy);
+ }
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_TAG: {
+ cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
+ if (item_copy == NULL) {
+ return NULL;
+ }
+ cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy);
+ cbor_decref(&item_copy);
+ return tag;
+ }
case CBOR_TYPE_FLOAT_CTRL:
return _cbor_copy_float_ctrl(item);
}
-
- return NULL;
}
#if CBOR_PRETTY_PRINTER
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, "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, "\n");
}
break;
- };
+ }
case CBOR_TYPE_ARRAY: {
fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " ");
if (cbor_array_is_definite(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)) {
_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);
+ _cbor_nested_describe(cbor_move(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)) {
fprintf(out, "value: %lf\n", cbor_float_get_float(item));
}
break;
- };
+ }
}
}
#include "cbor/tags.h"
#include "cbor/callbacks.h"
+#include "cbor/cbor_export.h"
#include "cbor/encoding.h"
#include "cbor/serialization.h"
#include "cbor/streaming.h"
* @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);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_load(
+ cbor_data source, size_t source_size, struct cbor_load_result* result);
-/** Deep copy of an item
+/** Take a 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
+ * @return **new** CBOR deep copy or `NULL` on failure.
*/
-cbor_item_t* cbor_copy(cbor_item_t* item);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+CBOR_EXPORT void cbor_describe(cbor_item_t* item, FILE* out);
#endif
#ifdef __cplusplus
#include "internal/memory_utils.h"
size_t cbor_array_size(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_array(item));
return item->metadata.array_metadata.allocated;
}
} else {
return false;
}
- // TODO: This is unreachable and the index checking logic above seems
- // suspicious -- out of bounds index is a caller error. Figure out & fix.
- return true;
}
bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) {
}
bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
- assert(cbor_isa_array(array));
+ CBOR_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;
/* Exponential realloc */
if (metadata->end_ptr >= metadata->allocated) {
// Check for overflows first
- // TODO: Explicitly test this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
return false;
}
}
bool cbor_array_is_definite(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_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));
+ CBOR_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));
+ CBOR_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));
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size);
_CBOR_DEPENDENT_NOTNULL(item, data);
return item;
}
-cbor_item_t *cbor_new_indefinite_array() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_array(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
#ifndef LIBCBOR_ARRAYS_H
#define LIBCBOR_ARRAYS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @param item[borrow] An array
* @return The number of members
*/
-size_t cbor_array_size(const cbor_item_t* item);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT size_t cbor_array_allocated(const cbor_item_t* item);
/** Get item by index
*
* @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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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
+ * If the index is out of bounds, the array is not modified and false is
+ * returned. 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);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_array_set(cbor_item_t* item, size_t index,
+ cbor_item_t* value);
/** Replace item at an index
*
* @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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_array_is_indefinite(const cbor_item_t* item);
/** Get the array contents
*
* @param item[borrow] An array
* @return #cbor_array_size items
*/
-cbor_item_t** cbor_array_handle(const cbor_item_t* item);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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();
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t* cbor_new_indefinite_array(void);
/** Append to the end
*
- * For indefinite items, storage may be realloacted. For definite items, only
+ * For indefinite items, storage may be reallocated. 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);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_array_push(cbor_item_t* array, cbor_item_t* pushee);
#ifdef __cplusplus
}
#include "internal/memory_utils.h"
size_t cbor_bytestring_length(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
return item->data;
}
bool cbor_bytestring_is_definite(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
return item->metadata.bytestring_metadata.type == _CBOR_METADATA_DEFINITE;
}
return !cbor_bytestring_is_definite(item);
}
-cbor_item_t *cbor_new_definite_bytestring() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_definite_bytestring(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
.refcount = 1,
.type = CBOR_TYPE_BYTESTRING,
- .metadata = {.bytestring_metadata = {_CBOR_METADATA_DEFINITE, 0}}};
+ .metadata = {.bytestring_metadata = {.type = _CBOR_METADATA_DEFINITE,
+ .length = 0}}};
return item;
}
-cbor_item_t *cbor_new_indefinite_bytestring() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_bytestring(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*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))};
+ .data = _cbor_malloc(sizeof(struct cbor_indefinite_string_data))};
_CBOR_DEPENDENT_NOTNULL(item, item->data);
*((struct cbor_indefinite_string_data *)item->data) =
(struct cbor_indefinite_string_data){
cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length) {
cbor_item_t *item = cbor_new_definite_bytestring();
_CBOR_NOTNULL(item);
- void *content = _CBOR_MALLOC(length);
+ void *content = _cbor_malloc(length);
_CBOR_DEPENDENT_NOTNULL(item, content);
memcpy(content, handle, length);
cbor_bytestring_set_handle(item, content, length);
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));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_bytestring(chunk));
+ CBOR_ASSERT(cbor_bytestring_is_definite(chunk));
struct cbor_indefinite_string_data *data =
(struct cbor_indefinite_string_data *)item->data;
if (data->chunk_count == data->chunk_capacity) {
- // TODO: Add a test for this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) {
return false;
}
#ifndef LIBCBOR_BYTESTRINGS_H
#define LIBCBOR_BYTESTRINGS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_bytestring_is_indefinite(const cbor_item_t *item);
/** Get the handle to the binary data
*
* @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);
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_mutable_data cbor_bytestring_handle(const cbor_item_t *item);
/** Set the handle to the binary data
*
* 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);
+CBOR_EXPORT 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
*
* @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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT size_t cbor_bytestring_chunk_count(const cbor_item_t *item);
/** Appends a chunk to the bytestring
*
* @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);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_bytestring_add_chunk(cbor_item_t *item,
+ cbor_item_t *chunk);
/** Creates a new definite byte string
*
*
* @return **new** definite bytestring. `NULL` on malloc failure.
*/
-cbor_item_t *cbor_new_definite_bytestring();
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t *cbor_new_definite_bytestring(void);
/** Creates a new indefinite byte string
*
- * The chunks array is initialized to `NULL` and chunkcount to 0
+ * The chunks array is initialized to `NULL` and chunk count to 0
*
* @return **new** indefinite bytestring. `NULL` on malloc failure.
*/
-cbor_item_t *cbor_new_indefinite_bytestring();
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t *cbor_new_indefinite_bytestring(void);
/** Creates a new byte string and initializes it
*
* @return A **new** byte string with content `handle`. `NULL` on malloc
* failure.
*/
-cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length);
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length);
#ifdef __cplusplus
}
#include "callbacks.h"
-#define CBOR_DUMMY_CALLBACK \
- {}
+void cbor_null_uint8_callback(void *_CBOR_UNUSED(_ctx),
+ uint8_t _CBOR_UNUSED(_val)) {}
-void cbor_null_uint8_callback(void *_ctx, uint8_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_uint16_callback(void *_CBOR_UNUSED(_ctx),
+ uint16_t _CBOR_UNUSED(_val)) {}
- void cbor_null_uint16_callback(void *_ctx,
- uint16_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_uint32_callback(void *_CBOR_UNUSED(_ctx),
+ uint32_t _CBOR_UNUSED(_val)) {}
- void cbor_null_uint32_callback(void *_ctx,
- uint32_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_uint64_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_uint64_callback(void *_ctx,
- uint64_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint8_callback(void *_CBOR_UNUSED(_ctx),
+ uint8_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint8_callback(void *_ctx,
- uint8_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint16_callback(void *_CBOR_UNUSED(_ctx),
+ uint16_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint16_callback(void *_ctx,
- uint16_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint32_callback(void *_CBOR_UNUSED(_ctx),
+ uint32_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint32_callback(void *_ctx,
- uint32_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint64_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint64_callback(void *_ctx,
- uint64_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_string_callback(void *_CBOR_UNUSED(_ctx),
+ cbor_data _CBOR_UNUSED(_val),
+ uint64_t _CBOR_UNUSED(_val2)) {}
- void cbor_null_string_callback(void *_ctx, cbor_data _val,
- size_t _val2) CBOR_DUMMY_CALLBACK
+void cbor_null_string_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_string_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_byte_string_callback(void *_CBOR_UNUSED(_ctx),
+ cbor_data _CBOR_UNUSED(_val),
+ uint64_t _CBOR_UNUSED(_val2)) {}
- 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 *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_byte_string_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_array_start_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_array_start_callback(void *_ctx,
- size_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_indef_array_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_indef_array_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_map_start_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_map_start_callback(void *_ctx,
- size_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_indef_map_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_indef_map_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_tag_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_tag_callback(void *_ctx, uint64_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_float2_callback(void *_CBOR_UNUSED(_ctx),
+ float _CBOR_UNUSED(_val)) {}
- void cbor_null_float2_callback(void *_ctx, float _val) CBOR_DUMMY_CALLBACK
+void cbor_null_float4_callback(void *_CBOR_UNUSED(_ctx),
+ float _CBOR_UNUSED(_val)) {}
- void cbor_null_float4_callback(void *_ctx, float _val) CBOR_DUMMY_CALLBACK
+void cbor_null_float8_callback(void *_CBOR_UNUSED(_ctx),
+ double _CBOR_UNUSED(_val)) {}
- void cbor_null_float8_callback(void *_ctx, double _val) CBOR_DUMMY_CALLBACK
+void cbor_null_null_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_null_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_undefined_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_undefined_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_boolean_callback(void *_CBOR_UNUSED(_ctx),
+ bool _CBOR_UNUSED(_val)) {}
- void cbor_null_boolean_callback(void *_ctx, bool _val) CBOR_DUMMY_CALLBACK
+void cbor_null_indef_break_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_indef_break_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+CBOR_EXPORT 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,
- 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 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 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 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 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 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 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,
- /* 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,
+ /* Shared indefinites */
+ .indef_break = cbor_null_indef_break_callback,
};
#ifndef LIBCBOR_CALLBACKS_H
#define LIBCBOR_CALLBACKS_H
+#include <stdint.h>
+
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
typedef void (*cbor_simple_callback)(void *);
/** Callback prototype */
-typedef void (*cbor_string_callback)(void *, cbor_data, size_t);
+typedef void (*cbor_string_callback)(void *, cbor_data, uint64_t);
/** Callback prototype */
-typedef void (*cbor_collection_callback)(void *, size_t);
+typedef void (*cbor_collection_callback)(void *, uint64_t);
/** Callback prototype */
typedef void (*cbor_float_callback)(void *, float);
};
/** Dummy callback implementation - does nothing */
-void cbor_null_uint8_callback(void *, uint8_t);
+CBOR_EXPORT void cbor_null_uint8_callback(void *, uint8_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_uint16_callback(void *, uint16_t);
+CBOR_EXPORT void cbor_null_uint16_callback(void *, uint16_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_uint32_callback(void *, uint32_t);
+CBOR_EXPORT void cbor_null_uint32_callback(void *, uint32_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_uint64_callback(void *, uint64_t);
+CBOR_EXPORT void cbor_null_uint64_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_negint8_callback(void *, uint8_t);
+CBOR_EXPORT void cbor_null_negint8_callback(void *, uint8_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_negint16_callback(void *, uint16_t);
+CBOR_EXPORT void cbor_null_negint16_callback(void *, uint16_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_negint32_callback(void *, uint32_t);
+CBOR_EXPORT void cbor_null_negint32_callback(void *, uint32_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_negint64_callback(void *, uint64_t);
+CBOR_EXPORT void cbor_null_negint64_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_string_callback(void *, cbor_data, size_t);
+CBOR_EXPORT void cbor_null_string_callback(void *, cbor_data, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_string_start_callback(void *);
+CBOR_EXPORT void cbor_null_string_start_callback(void *);
/** Dummy callback implementation - does nothing */
-void cbor_null_byte_string_callback(void *, cbor_data, size_t);
+CBOR_EXPORT void cbor_null_byte_string_callback(void *, cbor_data, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_byte_string_start_callback(void *);
+CBOR_EXPORT void cbor_null_byte_string_start_callback(void *);
/** Dummy callback implementation - does nothing */
-void cbor_null_array_start_callback(void *, size_t);
+CBOR_EXPORT void cbor_null_array_start_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_indef_array_start_callback(void *);
+CBOR_EXPORT void cbor_null_indef_array_start_callback(void *);
/** Dummy callback implementation - does nothing */
-void cbor_null_map_start_callback(void *, size_t);
+CBOR_EXPORT void cbor_null_map_start_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_indef_map_start_callback(void *);
+CBOR_EXPORT void cbor_null_indef_map_start_callback(void *);
/** Dummy callback implementation - does nothing */
-void cbor_null_tag_callback(void *, uint64_t);
+CBOR_EXPORT void cbor_null_tag_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
-void cbor_null_float2_callback(void *, float);
+CBOR_EXPORT void cbor_null_float2_callback(void *, float);
/** Dummy callback implementation - does nothing */
-void cbor_null_float4_callback(void *, float);
+CBOR_EXPORT void cbor_null_float4_callback(void *, float);
/** Dummy callback implementation - does nothing */
-void cbor_null_float8_callback(void *, double);
+CBOR_EXPORT void cbor_null_float8_callback(void *, double);
/** Dummy callback implementation - does nothing */
-void cbor_null_null_callback(void *);
+CBOR_EXPORT void cbor_null_null_callback(void *);
/** Dummy callback implementation - does nothing */
-void cbor_null_undefined_callback(void *);
+CBOR_EXPORT void cbor_null_undefined_callback(void *);
/** Dummy callback implementation - does nothing */
-void cbor_null_boolean_callback(void *, bool);
+CBOR_EXPORT void cbor_null_boolean_callback(void *, bool);
/** Dummy callback implementation - does nothing */
-void cbor_null_indef_break_callback(void *);
+CBOR_EXPORT void cbor_null_indef_break_callback(void *);
/** Dummy callback bundle - does nothing */
-extern const struct cbor_callbacks cbor_empty_callbacks;
+CBOR_EXPORT extern const struct cbor_callbacks cbor_empty_callbacks;
#ifdef __cplusplus
}
--- /dev/null
+
+#ifndef CBOR_EXPORT_H
+#define CBOR_EXPORT_H
+
+#ifdef CBOR_STATIC_DEFINE
+# define CBOR_EXPORT
+# define CBOR_NO_EXPORT
+#else
+# ifndef CBOR_EXPORT
+# ifdef cbor_EXPORTS
+ /* We are building this library */
+# define CBOR_EXPORT
+# else
+ /* We are using this library */
+# define CBOR_EXPORT
+# endif
+# endif
+
+# ifndef CBOR_NO_EXPORT
+# define CBOR_NO_EXPORT
+# endif
+#endif
+
+#ifndef CBOR_DEPRECATED
+# define CBOR_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+
+#ifndef CBOR_DEPRECATED_EXPORT
+# define CBOR_DEPRECATED_EXPORT CBOR_EXPORT CBOR_DEPRECATED
+#endif
+
+#ifndef CBOR_DEPRECATED_NO_EXPORT
+# define CBOR_DEPRECATED_NO_EXPORT CBOR_NO_EXPORT CBOR_DEPRECATED
+#endif
+
+#if 0 /* DEFINE_NO_DEPRECATED */
+# ifndef CBOR_NO_DEPRECATED
+# define CBOR_NO_DEPRECATED
+# endif
+#endif
+
+#endif /* CBOR_EXPORT_H */
#include "strings.h"
#include "tags.h"
+#ifdef DEBUG
+bool _cbor_enable_assert = true;
+#endif
+
bool cbor_isa_uint(const cbor_item_t *item) {
return item->type == CBOR_TYPE_UINT;
}
void cbor_decref(cbor_item_t **item_ref) {
cbor_item_t *item = *item_ref;
- assert(item->refcount > 0);
+ CBOR_ASSERT(item->refcount > 0);
if (--item->refcount == 0) {
switch (item->type) {
case CBOR_TYPE_UINT:
{ break; }
case CBOR_TYPE_BYTESTRING: {
if (cbor_bytestring_is_definite(item)) {
- _CBOR_FREE(item->data);
+ _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(
+ _cbor_free(
((struct cbor_indefinite_string_data *)item->data)->chunks);
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
}
break;
}
case CBOR_TYPE_STRING: {
if (cbor_string_is_definite(item)) {
- _CBOR_FREE(item->data);
+ _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(
+ _cbor_free(
((struct cbor_indefinite_string_data *)item->data)->chunks);
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
}
break;
}
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);
+ _cbor_free(item->data);
break;
}
case CBOR_TYPE_MAP: {
cbor_decref(&handle->key);
if (handle->value != NULL) cbor_decref(&handle->value);
}
- _CBOR_FREE(item->data);
+ _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);
+ _cbor_free(item->data);
break;
}
case CBOR_TYPE_FLOAT_CTRL: {
break;
}
}
- _CBOR_FREE(item);
- // TODO
+ _cbor_free(item);
*item_ref = NULL;
}
}
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+#include "cbor/cbor_export.h"
#include "cbor/configuration.h"
#include "data.h"
extern "C" {
/**
- * C++ is not a subset of C99 -- 'restrict' qualifier is not a part of the
+ * C99 is not a subset of C++ -- '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.
*
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_VERSION \
+ _CBOR_TO_STR(CBOR_MAJOR_VERSION) \
+ "." _CBOR_TO_STR(CBOR_MINOR_VERSION) "." _CBOR_TO_STR(CBOR_PATCH_VERSION)
#define CBOR_HEX_VERSION \
((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)
*/
#ifdef DEBUG
#include <stdio.h>
-#define debug_print(fmt, ...) \
+#define _cbor_debug_print(fmt, ...) \
do { \
if (DEBUG) \
fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \
__VA_ARGS__); \
} while (0)
+extern bool _cbor_enable_assert;
+// Like `assert`, but can be dynamically disabled in tests to allow testing
+// invalid behaviors.
+#define CBOR_ASSERT(e) assert(!_cbor_enable_assert || (e))
+#define _CBOR_TEST_DISABLE_ASSERT(block) \
+ do { \
+ _cbor_enable_assert = false; \
+ block _cbor_enable_assert = true; \
+ } while (0)
#else
#define debug_print(fmt, ...) \
do { \
} while (0)
+#define CBOR_ASSERT(e)
+#define _CBOR_TEST_DISABLE_ASSERT(block) \
+ do { \
+ block \
+ } while (0)
+#endif
+
+#define _CBOR_TO_STR_(x) #x
+#define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */
+
+#ifdef __GNUC__
+#define _CBOR_UNUSED(x) __attribute__((__unused__)) x
+// TODO(https://github.com/PJK/libcbor/issues/247): Prefer [[nodiscard]] if
+// available
+#define _CBOR_NODISCARD __attribute__((warn_unused_result))
+#elif defined(_MSC_VER)
+#define _CBOR_UNUSED(x) __pragma(warning(suppress : 4100 4101)) x
+#define _CBOR_NODISCARD
+#else
+#define _CBOR_UNUSED(x) x
+#define _CBOR_NODISCARD
#endif
-#define TO_STR_(x) #x
-#define TO_STR(x) TO_STR_(x) /* enables proper double expansion */
+#if 0 /* custom allocators are not supported on OpenBSD */
+typedef void *(*_cbor_malloc_t)(size_t);
+typedef void *(*_cbor_realloc_t)(void *, size_t);
+typedef void (*_cbor_free_t)(void *);
+
+CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc;
+CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc;
+CBOR_EXPORT extern _cbor_free_t _cbor_free;
+#endif
// Macro to short-circuit builder functions when memory allocation fails
#define _CBOR_NOTNULL(cbor_item) \
#define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \
do { \
if (pointer == NULL) { \
- _CBOR_FREE(cbor_item); \
+ _cbor_free(cbor_item); \
return NULL; \
} \
} while (0)
-#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.
+ * 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
- * (see e.g. http://en.cppreference.com/w/c/memory/realloc) \endrst
+ * (see e.g. http://en.cppreference.com/w/c/memory/realloc)
+ * \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
-
+#if 0 /* not on OpenBSD */
+CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc,
+ _cbor_realloc_t custom_realloc,
+ _cbor_free_t custom_free);
#endif
/*
* @param item[borrow]
* @return The type
*/
-cbor_type cbor_typeof(
+_CBOR_NODISCARD
+CBOR_EXPORT 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 */
* @param item[borrow] the item
* @return Is the item an #CBOR_TYPE_UINT?
*/
-bool cbor_isa_uint(const cbor_item_t *item);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t *item);
/* Practical types with respect to their semantics (but not tag values) */
* @param item[borrow] the item
* @return Is the item an integer, either positive or negative?
*/
-bool cbor_is_int(const cbor_item_t *item);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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
+ * 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);
+_CBOR_NODISCARD
+CBOR_EXPORT 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
+ * C.
+ * \endrst
+ *
* @param item[borrow] the item
* @return Is the item (CBOR logical) undefined?
*/
-bool cbor_is_undef(const cbor_item_t *item);
+_CBOR_NODISCARD
+CBOR_EXPORT bool cbor_is_undef(const cbor_item_t *item);
/*
* ============================================================================
* @param item[incref] item the item
* @return the input reference
*/
-cbor_item_t *cbor_incref(cbor_item_t *item);
+CBOR_EXPORT cbor_item_t *cbor_incref(cbor_item_t *item);
/** Decreases the reference count by one, deallocating the item if needed
*
*
* @param item[take] the item. Set to `NULL` if deallocated
*/
-void cbor_decref(cbor_item_t **item);
+CBOR_EXPORT void cbor_decref(cbor_item_t **item);
/** Decreases the reference count by one, deallocating the item if needed
*
*
* @param item[take] the item
*/
-void cbor_intermediate_decref(cbor_item_t *item);
+CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t *item);
/** Get the reference count
*
* @param item[borrow] the item
* @return the reference count
*/
-size_t cbor_refcount(const cbor_item_t *item);
+_CBOR_NODISCARD
+CBOR_EXPORT size_t cbor_refcount(const cbor_item_t *item);
/** Provides CPP-like move construct
*
*
* \rst
* .. warning:: If the item is moved without correctly increasing the reference
- * count afterwards, the memory will be leaked. \endrst
+ * 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);
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t *cbor_move(cbor_item_t *item);
#ifdef __cplusplus
}
#define LIBCBOR_CONFIGURATION_H
#define CBOR_MAJOR_VERSION 0
-#define CBOR_MINOR_VERSION 7
+#define CBOR_MINOR_VERSION 10
#define CBOR_PATCH_VERSION 0
-#define CBOR_CUSTOM_ALLOC 0
#define CBOR_BUFFER_GROWTH 2
#define CBOR_MAX_STACK_SIZE 2048
#define CBOR_PRETTY_PRINTER 1
#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}
#define CBOR_MAX_STACK_SIZE ${CBOR_MAX_STACK_SIZE}
#cmakedefine01 CBOR_PRETTY_PRINTER
CBOR_ERR_NONE,
CBOR_ERR_NOTENOUGHDATA,
CBOR_ERR_NODATA,
+ // TODO: Should be "malformed" or at least "malformatted". Retained for
+ // backwards compatibility.
CBOR_ERR_MALFORMATED,
CBOR_ERR_MEMERROR /** Memory error - item allocation failed. Is it too big for
your allocator? */
CBOR_CTRL_UNDEF = 23
} _cbor_ctrl;
+// Metadata items use size_t (instead of uint64_t) because items in memory take
+// up at least 1B per entry or string byte, so if size_t is narrower than
+// uint64_t, we wouldn't be able to create them in the first place and can save
+// some space.
+
/** Integers specific metadata */
struct _cbor_int_metadata {
cbor_int_width width;
struct cbor_load_result {
/** Error indicator */
struct cbor_error error;
- /** Number of bytes read*/
+ /** 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 */
+ /** Decoding finished successfully (a callback has been invoked)
+ *
+ * Note that this does *not* mean that the buffer has been fully decoded;
+ * there may still be unread bytes for which no callback has been involved.
+ */
+ CBOR_DECODER_FINISHED,
+ /** Not enough data to invoke a callback */
+ // TODO: The name is inconsistent with CBOR_ERR_NOTENOUGHDATA. Retained for
+ // backwards compatibility.
+ CBOR_DECODER_NEDATA,
+ /** Bad data (reserved MTB, malformed value, etc.) */
+ CBOR_DECODER_ERROR
};
/** Streaming decoder result */
struct cbor_decoder_result {
- /** Bytes read */
+ /** Input bytes read/consumed
+ *
+ * If this is less than the size of input buffer, the client will likely
+ * resume parsing starting at the next byte (e.g. `buffer + result.read`).
+ *
+ * Set to 0 if the #status is not #CBOR_DECODER_FINISHED.
+ */
size_t read;
- /** The result */
+
+ /** The decoding status */
enum cbor_decoder_status status;
- /** When status == CBOR_DECODER_NEDATA,
- * the minimum number of bytes required to continue parsing */
+
+ /** Number of bytes in the input buffer needed to resume parsing
+ *
+ * Set to 0 unless the result status is #CBOR_DECODER_NEDATA. If it is, then:
+ * - If at least one byte was passed, #required will be set to the minimum
+ * number of bytes needed to invoke a decoded callback on the current
+ * prefix.
+ *
+ * For example: Attempting to decode a 1B buffer containing `0x19` will
+ * set #required to 3 as `0x19` signals a 2B integer item, so we need at
+ * least 3B to continue (the `0x19` MTB byte and two bytes of data needed
+ * to invoke #cbor_callbacks.uint16).
+ *
+ * - If there was no data at all, #read will always be set to 1
+ */
size_t required;
};
val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
if (exp == 0xFF) { /* Infinity or NaNs */
if (value != value) {
- res = (uint16_t)0x007e00; /* Not IEEE semantics - required by CBOR
- [s. 3.9] */
+ // We discard information bits in half-float NaNs. This is
+ // not required for the core CBOR protocol (it is only a suggestion in
+ // Section 3.9).
+ // See https://github.com/PJK/libcbor/issues/215
+ res = (uint16_t)0x007e00;
} else {
- res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u |
- (mant ? 1u : 0u) << 15u);
+ // If the mantissa is non-zero, we have a NaN, but those are handled
+ // above. See
+ // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+ CBOR_ASSERT(mant == 0u);
+ res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
}
} else if (exp == 0x00) { /* Zeroes or subnorms */
res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
} else { /* Normal numbers */
int8_t logical_exp = (int8_t)(exp - 127);
- assert(logical_exp == exp - 127);
+ CBOR_ASSERT(logical_exp == exp - 127);
// Now we know that 2^exp <= 0 logically
if (logical_exp < -24) {
value is lost. This is an implementation decision that works around the
absence of standard half-float in the language. */
res = (uint16_t)((val & 0x80000000u) >> 16u) | // Extract sign bit
- (uint16_t)(1u << (24u + logical_exp));
+ ((uint16_t)(1u << (24u + logical_exp)) +
+ (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
+ 1)); // Round half away from zero for simplicity
} else {
res = (uint16_t)((val & 0x80000000u) >> 16u |
((((uint8_t)logical_exp) + 15u) << 10u) |
#ifndef LIBCBOR_ENCODING_H
#define LIBCBOR_ENCODING_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
#endif
/*
- * ============================================================================
- * Primitives encoding
- * ============================================================================
+ * All cbor_encode_* methods take 2 or 3 arguments:
+ * - a logical `value` to encode (except for trivial items such as NULLs)
+ * - an output `buffer` pointer
+ * - a `buffer_size` specification
+ *
+ * They serialize the `value` into one or more bytes and write the bytes to the
+ * output `buffer` and return either the number of bytes written, or 0 if the
+ * `buffer_size` was too small to small to fit the serialized value (in which
+ * case it is not modified).
*/
-size_t cbor_encode_uint8(uint8_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint8(uint8_t, unsigned char *,
+ size_t);
-size_t cbor_encode_uint16(uint16_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint16(uint16_t, unsigned char *,
+ size_t);
-size_t cbor_encode_uint32(uint32_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint32(uint32_t, unsigned char *,
+ size_t);
-size_t cbor_encode_uint64(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint64(uint64_t, unsigned char *,
+ size_t);
-size_t cbor_encode_uint(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint(uint64_t, unsigned char *,
+ size_t);
-size_t cbor_encode_negint8(uint8_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint8(uint8_t, unsigned char *,
+ size_t);
-size_t cbor_encode_negint16(uint16_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint16(uint16_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_negint32(uint32_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint32(uint32_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_negint64(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint64(uint64_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_negint(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint(uint64_t, unsigned char *,
+ size_t);
-size_t cbor_encode_bytestring_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_bytestring_start(size_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_indef_bytestring_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_encode_indef_bytestring_start(unsigned char *, size_t);
-size_t cbor_encode_string_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_string_start(size_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_indef_string_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_encode_indef_string_start(unsigned char *, size_t);
-size_t cbor_encode_array_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_array_start(size_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_indef_array_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_encode_indef_array_start(unsigned char *, size_t);
-size_t cbor_encode_map_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_map_start(size_t,
+ unsigned char *,
+ size_t);
-size_t cbor_encode_indef_map_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_indef_map_start(unsigned char *,
+ size_t);
-size_t cbor_encode_tag(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_tag(uint64_t, unsigned char *,
+ size_t);
-size_t cbor_encode_bool(bool, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_bool(bool, unsigned char *,
+ size_t);
-size_t cbor_encode_null(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_null(unsigned char *, size_t);
-size_t cbor_encode_undef(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_undef(unsigned char *, size_t);
/** Encodes a half-precision float
*
* 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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_half(float, unsigned char *,
+ size_t);
-size_t cbor_encode_single(float, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_single(float, unsigned char *,
+ size_t);
-size_t cbor_encode_double(double, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_double(double, unsigned char *,
+ size_t);
-size_t cbor_encode_break(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_break(unsigned char *, size_t);
-size_t cbor_encode_ctrl(uint8_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_ctrl(uint8_t, unsigned char *,
+ size_t);
#ifdef __cplusplus
}
#include "assert.h"
cbor_float_width cbor_float_get_width(const cbor_item_t *item) {
- assert(cbor_isa_float_ctrl(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_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));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_is_float(item));
+ // cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return NAN;
case CBOR_FLOAT_64:
return cbor_float_get_float8(item);
}
- return NAN; /* Compiler complaints */
}
bool cbor_get_bool(const cbor_item_t *item) {
- assert(cbor_is_bool(item));
+ CBOR_ASSERT(cbor_is_bool(item));
return item->metadata.float_ctrl_metadata.ctrl == CBOR_CTRL_TRUE;
}
void cbor_set_float2(cbor_item_t *item, float value) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_16);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_0);
item->metadata.float_ctrl_metadata.ctrl = value;
}
void cbor_set_bool(cbor_item_t *item, bool value) {
- assert(cbor_is_bool(item));
+ CBOR_ASSERT(cbor_is_bool(item));
item->metadata.float_ctrl_metadata.ctrl =
value ? CBOR_CTRL_TRUE : CBOR_CTRL_FALSE;
}
-cbor_item_t *cbor_new_ctrl() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_ctrl(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
return item;
}
-cbor_item_t *cbor_new_float2() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
+cbor_item_t *cbor_new_float2(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 4);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
return item;
}
-cbor_item_t *cbor_new_float4() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
+cbor_item_t *cbor_new_float4(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 4);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
return item;
}
-cbor_item_t *cbor_new_float8() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8);
+cbor_item_t *cbor_new_float8(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 8);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
return item;
}
-cbor_item_t *cbor_new_null() {
+cbor_item_t *cbor_new_null(void) {
cbor_item_t *item = cbor_new_ctrl();
_CBOR_NOTNULL(item);
cbor_set_ctrl(item, CBOR_CTRL_NULL);
return item;
}
-cbor_item_t *cbor_new_undef() {
+cbor_item_t *cbor_new_undef(void) {
cbor_item_t *item = cbor_new_ctrl();
_CBOR_NOTNULL(item);
cbor_set_ctrl(item, CBOR_CTRL_UNDEF);
#ifndef LIBCBOR_FLOATS_CTRLS_H
#define LIBCBOR_FLOATS_CTRLS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT cbor_float_width
+cbor_float_get_width(const cbor_item_t *item);
/** Get a half precision float
*
* @param[borrow] A half precision float
* @return half precision value
*/
-float cbor_float_get_float2(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT 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
+ * @param[borrow] A single precision float
* @return single precision value
*/
-float cbor_float_get_float4(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT float cbor_float_get_float4(
+ const cbor_item_t *item);
/** Get a double precision float
*
* @param[borrow] A double precision float
* @return double precision value
*/
-double cbor_float_get_float8(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT double cbor_float_get_float8(
+ const cbor_item_t *item);
/** Get the float value represented as double
*
* @param[borrow] Any float
* @return double precision value
*/
-double cbor_float_get_float(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT double cbor_float_get_float(
+ const cbor_item_t *item);
/** Get value from a boolean ctrl item
*
* @param item[borrow] A ctrl item
* @return boolean value
*/
-bool cbor_get_bool(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_get_bool(const cbor_item_t *item);
/** Constructs a new ctrl item
*
*
* @return **new** 1B ctrl or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_new_ctrl();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_ctrl(void);
/** Constructs a new float item
*
*
* @return **new** 2B float or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_new_float2();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_float2(void);
/** Constructs a new float item
*
*
* @return **new** 4B float or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_new_float4();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_float4(void);
/** Constructs a new float item
*
*
* @return **new** 8B float or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_new_float8();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_float8(void);
/** Constructs new null ctrl item
*
* @return **new** null ctrl item or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_new_null();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_null(void);
/** Constructs new undef ctrl item
*
* @return **new** undef ctrl item or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_new_undef();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_undef(void);
/** Constructs new boolean ctrl item
*
* @param value The value to use
* @return **new** boolean ctrl item or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_build_bool(bool value);
+_CBOR_NODISCARD CBOR_EXPORT 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.
+ * 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);
+CBOR_EXPORT void cbor_set_ctrl(cbor_item_t *item, uint8_t value);
/** Assign a boolean value to a boolean ctrl item
*
* @param item[borrow] A ctrl item
* @param value The simple value to assign.
*/
-void cbor_set_bool(cbor_item_t *item, bool value);
+CBOR_EXPORT void cbor_set_bool(cbor_item_t *item, bool 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);
+CBOR_EXPORT 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);
+CBOR_EXPORT 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);
+CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT uint8_t cbor_ctrl_value(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);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_float2(float value);
/** Constructs a new float
*
* @param value the value to use
* @return **new** float or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_build_float4(float value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_float4(float value);
/** Constructs a new float
*
* @param value the value to use
* @return **new** float or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_build_float8(double value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_float8(double value);
/** Constructs a ctrl item
*
* @param value the value to use
* @return **new** ctrl item or `NULL` upon memory allocation failure
*/
-cbor_item_t *cbor_build_ctrl(uint8_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_ctrl(uint8_t value);
#ifdef __cplusplus
}
*/
#include "builder_callbacks.h"
+
#include <string.h>
+
#include "../arrays.h"
#include "../bytestrings.h"
+#include "../common.h"
#include "../floats_ctrls.h"
#include "../ints.h"
#include "../maps.h"
#include "../tags.h"
#include "unicode.h"
+// `_cbor_builder_append` takes ownership of `item`. If adding the item to
+// parent container fails, `item` will be deallocated to prevent memory.
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)) {
- /*
- * We don't need an explicit check for whether the item still belongs
- * into this array because if there are extra items, they will cause a
- * syntax error when decoded.
- */
- 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);
+ return;
+ }
+ /* Part of a bigger structure */
+ switch (ctx->stack->top->item->type) {
+ // Handle Arrays and Maps since they can contain subitems of any type.
+ // Byte/string construction from chunks is handled in the respective chunk
+ // handlers.
+ case CBOR_TYPE_ARRAY: {
+ if (cbor_array_is_definite(ctx->stack->top->item)) {
+ // We don't need an explicit check for whether the item still belongs
+ // into this array because if there are extra items, they will cause a
+ // syntax error when decoded.
+ CBOR_ASSERT(ctx->stack->top->subitems > 0);
+ // This should never happen since the definite array should be
+ // preallocated for the expected number of items.
+ if (!cbor_array_push(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
cbor_decref(&item);
+ break;
}
- 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));
+ cbor_decref(&item);
+ ctx->stack->top->subitems--;
+ if (ctx->stack->top->subitems == 0) {
+ cbor_item_t *stack_item = ctx->stack->top->item;
+ _cbor_stack_pop(ctx->stack);
+ _cbor_builder_append(stack_item, ctx);
}
- 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 */
+ } else {
+ /* Indefinite array, don't bother with subitems */
+ if (!cbor_array_push(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
}
- break;
+ cbor_decref(&item);
}
- 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;
+ break;
+ }
+ case CBOR_TYPE_MAP: {
+ // Handle both definite and indefinite maps the same initially.
+ // Note: 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 */
+ if (!_cbor_map_add_value(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
+ cbor_decref(&item);
+ break;
+ }
+ } else {
+ /* Even record, this is a key */
+ if (!_cbor_map_add_key(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
+ cbor_decref(&item);
+ break;
+ }
}
- default: {
- cbor_decref(&item);
- ctx->syntax_error = true;
+ cbor_decref(&item);
+ if (cbor_map_is_definite(ctx->stack->top->item)) {
+ CBOR_ASSERT(ctx->stack->top->subitems > 0);
+ ctx->stack->top->subitems--;
+ if (ctx->stack->top->subitems == 0) {
+ cbor_item_t *map_entry = ctx->stack->top->item;
+ _cbor_stack_pop(ctx->stack);
+ _cbor_builder_append(map_entry, ctx);
+ }
+ } else {
+ ctx->stack->top->subitems ^=
+ 1; /* Flip the indicator for indefinite items */
}
+ break;
+ }
+ case CBOR_TYPE_TAG: {
+ CBOR_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 *tagged_item = ctx->stack->top->item;
+ _cbor_stack_pop(ctx->stack);
+ _cbor_builder_append(tagged_item, ctx);
+ break;
+ }
+ // We have an item to append but nothing to append it to.
+ default: {
+ cbor_decref(&item);
+ ctx->syntax_error = true;
}
}
}
} \
} while (0)
+// Check that the length fits into size_t. If not, we cannot possibly allocate
+// the required memory and should fail fast.
+#define CHECK_LENGTH(ctx, length) \
+ do { \
+ if (length > SIZE_MAX) { \
+ ctx->creation_failed = true; \
+ return; \
+ } \
+ } while (0)
+
#define PUSH_CTX_STACK(ctx, res, subitems) \
do { \
if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \
void cbor_builder_negint16_callback(void *context, uint16_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int16();
+ CHECK_RES(ctx, res);
cbor_mark_negint(res);
cbor_set_uint16(res, value);
_cbor_builder_append(res, ctx);
}
void cbor_builder_byte_string_callback(void *context, cbor_data data,
- size_t length) {
+ uint64_t length) {
struct _cbor_decoder_context *ctx = context;
- unsigned char *new_handle = _CBOR_MALLOC(length);
+ CHECK_LENGTH(ctx, length);
+ unsigned char *new_handle = _cbor_malloc(length);
if (new_handle == NULL) {
ctx->creation_failed = true;
return;
}
memcpy(new_handle, data, length);
- cbor_item_t *res = cbor_new_definite_bytestring();
+ cbor_item_t *new_chunk = cbor_new_definite_bytestring();
- if (res == NULL) {
- _CBOR_FREE(new_handle);
+ if (new_chunk == NULL) {
+ _cbor_free(new_handle);
ctx->creation_failed = true;
return;
}
- cbor_bytestring_set_handle(res, new_handle, length);
+ cbor_bytestring_set_handle(new_chunk, 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;
+ // If an indef bytestring is on the stack, extend it (if it were closed, it
+ // would have been popped). Handle any syntax errors upstream.
+ if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item) &&
+ cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
+ if (!cbor_bytestring_add_chunk(ctx->stack->top->item, new_chunk)) {
+ ctx->creation_failed = true;
}
+ cbor_decref(&new_chunk);
} else {
- _cbor_builder_append(res, ctx);
+ _cbor_builder_append(new_chunk, ctx);
}
}
}
void cbor_builder_string_callback(void *context, cbor_data data,
- size_t length) {
+ uint64_t length) {
struct _cbor_decoder_context *ctx = context;
+ CHECK_LENGTH(ctx, length);
struct _cbor_unicode_status unicode_status;
-
- size_t codepoint_count =
+ uint64_t codepoint_count =
_cbor_unicode_codepoint_count(data, length, &unicode_status);
- if (unicode_status.status == _CBOR_UNICODE_BADCP) {
+ if (unicode_status.status != _CBOR_UNICODE_OK) {
ctx->syntax_error = true;
return;
}
+ CBOR_ASSERT(codepoint_count <= length);
- unsigned char *new_handle = _CBOR_MALLOC(length);
+ unsigned char *new_handle = _cbor_malloc(length);
if (new_handle == NULL) {
ctx->creation_failed = true;
}
memcpy(new_handle, data, length);
- cbor_item_t *res = cbor_new_definite_string();
- if (res == NULL) {
- _CBOR_FREE(new_handle);
+ cbor_item_t *new_chunk = cbor_new_definite_string();
+ if (new_chunk == NULL) {
+ _cbor_free(new_handle);
ctx->creation_failed = true;
return;
}
- cbor_string_set_handle(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;
+ cbor_string_set_handle(new_chunk, new_handle, length);
+ new_chunk->metadata.string_metadata.codepoint_count = codepoint_count;
+
+ // If an indef string is on the stack, extend it (if it were closed, it would
+ // have been popped). Handle any syntax errors upstream.
+ if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) &&
+ cbor_string_is_indefinite(ctx->stack->top->item)) {
+ if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) {
+ ctx->creation_failed = true;
}
+ cbor_decref(&new_chunk);
} else {
- _cbor_builder_append(res, ctx);
+ _cbor_builder_append(new_chunk, ctx);
}
}
PUSH_CTX_STACK(ctx, res, 0);
}
-void cbor_builder_array_start_callback(void *context, size_t size) {
+void cbor_builder_array_start_callback(void *context, uint64_t size) {
struct _cbor_decoder_context *ctx = context;
+ CHECK_LENGTH(ctx, size);
cbor_item_t *res = cbor_new_definite_array(size);
CHECK_RES(ctx, res);
if (size > 0) {
PUSH_CTX_STACK(ctx, res, 0);
}
-void cbor_builder_map_start_callback(void *context, size_t size) {
+void cbor_builder_map_start_callback(void *context, uint64_t size) {
struct _cbor_decoder_context *ctx = context;
+ CHECK_LENGTH(ctx, size);
cbor_item_t *res = cbor_new_definite_map(size);
CHECK_RES(ctx, res);
if (size > 0) {
bool _cbor_is_indefinite(cbor_item_t *item) {
switch (item->type) {
case CBOR_TYPE_BYTESTRING:
- return item->metadata.bytestring_metadata.type ==
- _CBOR_METADATA_INDEFINITE;
+ return cbor_bytestring_is_indefinite(item);
case CBOR_TYPE_STRING:
- return item->metadata.string_metadata.type == _CBOR_METADATA_INDEFINITE;
+ return cbor_string_is_indefinite(item);
case CBOR_TYPE_ARRAY:
- return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
+ return cbor_array_is_indefinite(item);
case CBOR_TYPE_MAP:
- return item->metadata.map_metadata.type == _CBOR_METADATA_INDEFINITE;
+ return cbor_map_is_indefinite(item);
default:
return false;
}
void cbor_builder_float2_callback(void *context, float value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_float2();
+ CHECK_RES(ctx, res);
cbor_set_float2(res, value);
_cbor_builder_append(res, ctx);
}
struct _cbor_stack *stack;
};
+/** Internal helper: Append item to the top of the stack while handling errors.
+ */
+void _cbor_builder_append(cbor_item_t *item, struct _cbor_decoder_context *ctx);
+
void cbor_builder_uint8_callback(void *, uint8_t);
void cbor_builder_uint16_callback(void *, uint16_t);
void cbor_builder_negint64_callback(void *, uint64_t);
-void cbor_builder_string_callback(void *, cbor_data, size_t);
+void cbor_builder_string_callback(void *, cbor_data, uint64_t);
void cbor_builder_string_start_callback(void *);
-void cbor_builder_byte_string_callback(void *, cbor_data, size_t);
+void cbor_builder_byte_string_callback(void *, cbor_data, uint64_t);
void cbor_builder_byte_string_start_callback(void *);
-void cbor_builder_array_start_callback(void *, size_t);
+void cbor_builder_array_start_callback(void *, uint64_t);
void cbor_builder_indef_array_start_callback(void *);
-void cbor_builder_map_start_callback(void *, size_t);
+void cbor_builder_map_start_callback(void *, uint64_t);
void cbor_builder_indef_map_start_callback(void *);
#ifdef IS_BIG_ENDIAN
memcpy(buffer + 1, &value, 2);
#else
- buffer[1] = value >> 8;
- buffer[2] = value;
+ buffer[1] = (unsigned char)(value >> 8);
+ buffer[2] = (unsigned char)value;
#endif
return 3;
#ifdef IS_BIG_ENDIAN
memcpy(buffer + 1, &value, 4);
#else
- buffer[1] = value >> 24;
- buffer[2] = value >> 16;
- buffer[3] = value >> 8;
- buffer[4] = value;
+ buffer[1] = (unsigned char)(value >> 24);
+ buffer[2] = (unsigned char)(value >> 16);
+ buffer[3] = (unsigned char)(value >> 8);
+ buffer[4] = (unsigned char)value;
#endif
return 5;
#ifdef IS_BIG_ENDIAN
memcpy(buffer + 1, &value, 8);
#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;
+ buffer[1] = (unsigned char)(value >> 56);
+ buffer[2] = (unsigned char)(value >> 48);
+ buffer[3] = (unsigned char)(value >> 40);
+ buffer[4] = (unsigned char)(value >> 32);
+ buffer[5] = (unsigned char)(value >> 24);
+ buffer[6] = (unsigned char)(value >> 16);
+ buffer[7] = (unsigned char)(value >> 8);
+ buffer[8] = (unsigned char)value;
#endif
return 9;
extern "C" {
#endif
+_CBOR_NODISCARD
size_t _cbor_encode_uint8(uint8_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint16(uint16_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint32(uint32_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint64(uint64_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint(uint64_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
return (float)(half & 0x8000 ? -val : val);
}
-double _cbor_load_half(cbor_data source) {
+float _cbor_load_half(cbor_data source) {
/* Discard const */
return _cbor_decode_half((unsigned char *)source);
}
#endif
/* Read the given uint from the given location, no questions asked */
+_CBOR_NODISCARD
uint8_t _cbor_load_uint8(const unsigned char *source);
+_CBOR_NODISCARD
uint16_t _cbor_load_uint16(const unsigned char *source);
+_CBOR_NODISCARD
uint32_t _cbor_load_uint32(const unsigned char *source);
+_CBOR_NODISCARD
uint64_t _cbor_load_uint64(const unsigned char *source);
-double _cbor_load_half(cbor_data source);
+_CBOR_NODISCARD
+float _cbor_load_half(cbor_data source);
+_CBOR_NODISCARD
float _cbor_load_float(cbor_data source);
+_CBOR_NODISCARD
double _cbor_load_double(cbor_data source);
#ifdef __cplusplus
}
bool _cbor_safe_to_multiply(size_t a, size_t b) {
+ if (a <= 1 || b <= 1) return true;
return _cbor_highest_bit(a) + _cbor_highest_bit(b) <= sizeof(size_t) * 8;
}
+bool _cbor_safe_to_add(size_t a, size_t b) {
+ // Unsigned integer overflow doesn't constitute UB
+ size_t sum = a + b;
+ return sum >= a && sum >= b;
+}
+
+size_t _cbor_safe_signaling_add(size_t a, size_t b) {
+ if (a == 0 || b == 0) return 0;
+ if (_cbor_safe_to_add(a, b)) return a + b;
+ return 0;
+}
+
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);
+ 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);
+ return _cbor_realloc(pointer, item_size * item_count);
} else {
return NULL;
}
#include <stdbool.h>
#include <string.h>
-/** Can a and b be multiplied without overflowing size_t? */
+#include "cbor/common.h"
+
+/** Can `a` and `b` be multiplied without overflowing size_t? */
+_CBOR_NODISCARD
bool _cbor_safe_to_multiply(size_t a, size_t b);
+/** Can `a` and `b` be added without overflowing size_t? */
+_CBOR_NODISCARD
+bool _cbor_safe_to_add(size_t a, size_t b);
+
+/** Adds `a` and `b`, propagating zeros and returing 0 on overflow. */
+_CBOR_NODISCARD
+size_t _cbor_safe_signaling_add(size_t a, size_t b);
+
/** Overflow-proof contiguous array allocation
*
* @param item_size
#include "stack.h"
-struct _cbor_stack _cbor_stack_init() {
+struct _cbor_stack _cbor_stack_init(void) {
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);
+ _cbor_free(top);
stack->size--;
}
size_t subitems) {
if (stack->size == CBOR_MAX_STACK_SIZE) return NULL;
struct _cbor_stack_record *new_top =
- _CBOR_MALLOC(sizeof(struct _cbor_stack_record));
+ _cbor_malloc(sizeof(struct _cbor_stack_record));
if (new_top == NULL) return NULL;
*new_top = (struct _cbor_stack_record){stack->top, item, subitems};
/** Simple stack record for the parser */
struct _cbor_stack_record {
+ /** Pointer to the parent stack frame */
struct _cbor_stack_record *lower;
+ /** Item under construction */
cbor_item_t *item;
+ /**
+ * How many outstanding subitems are expected.
+ *
+ * For example, when we see a new definite array, `subitems` is initialized to
+ * the array length. With every item added, the counter is decreased. When it
+ * reaches zero, the stack is popped and the complete item is propagated
+ * upwards.
+ */
size_t subitems;
};
size_t size;
};
-struct _cbor_stack _cbor_stack_init();
+_CBOR_NODISCARD
+struct _cbor_stack _cbor_stack_init(void);
void _cbor_stack_pop(struct _cbor_stack *);
+_CBOR_NODISCARD
struct _cbor_stack_record *_cbor_stack_push(struct _cbor_stack *, cbor_item_t *,
size_t);
*/
#include "unicode.h"
+#include <stdint.h>
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
return *state;
}
-size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
- struct _cbor_unicode_status* status) {
+uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_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;
+ uint64_t pos = 0, count = 0;
for (; pos < source_length; pos++) {
res = _cbor_unicode_decode(&state, &codepoint, source[pos]);
error:
*status = (struct _cbor_unicode_status){.location = pos,
.status = _CBOR_UNICODE_BADCP};
- return -1;
+ return 0;
}
/** Signals unicode validation error and possibly its location */
struct _cbor_unicode_status {
enum _cbor_unicode_status_error status;
- size_t location;
+ uint64_t location;
};
-size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
- struct _cbor_unicode_status* status);
+_CBOR_NODISCARD
+uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length,
+ struct _cbor_unicode_status* status);
#ifdef __cplusplus
}
#include "ints.h"
cbor_int_width cbor_int_get_width(const cbor_item_t *item) {
- assert(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_is_int(item));
+ // cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_get_uint8(item);
case CBOR_INT_64:
return cbor_get_uint64(item);
}
- // TODO: This should be handled in a default branch
- 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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_is_int(item));
item->type = CBOR_TYPE_UINT;
}
void cbor_mark_negint(cbor_item_t *item) {
- assert(cbor_is_int(item));
+ CBOR_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);
+cbor_item_t *cbor_new_int8(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 1);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
return item;
}
-cbor_item_t *cbor_new_int16() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 2);
+cbor_item_t *cbor_new_int16(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 2);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
return item;
}
-cbor_item_t *cbor_new_int32() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
+cbor_item_t *cbor_new_int32(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 4);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
return item;
}
-cbor_item_t *cbor_new_int64() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8);
+cbor_item_t *cbor_new_int64(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 8);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
#ifndef LIBCBOR_INTS_H
#define LIBCBOR_INTS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @param item[borrow] positive or negative integer
* @return the value
*/
-uint8_t cbor_get_uint8(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT uint64_t cbor_get_int(const cbor_item_t *item);
/** Assigns the integer value
*
* @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);
+CBOR_EXPORT void cbor_set_uint8(cbor_item_t *item, uint8_t value);
/** Assigns the integer value
*
* @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);
+CBOR_EXPORT void cbor_set_uint16(cbor_item_t *item, uint16_t value);
/** Assigns the integer value
*
* @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);
+CBOR_EXPORT void cbor_set_uint32(cbor_item_t *item, uint32_t value);
/** Assigns the integer value
*
* @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);
+CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT cbor_int_width
+cbor_int_get_width(const cbor_item_t *item);
/** Marks the integer item as a positive integer
*
*
* @param item[borrow] positive or negative integer item
*/
-void cbor_mark_uint(cbor_item_t *item);
+CBOR_EXPORT void cbor_mark_uint(cbor_item_t *item);
/** Marks the integer item as a negative integer
*
*
* @param item[borrow] positive or negative integer item
*/
-void cbor_mark_negint(cbor_item_t *item);
+CBOR_EXPORT void cbor_mark_negint(cbor_item_t *item);
/** Allocates new integer with 1B width
*
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-cbor_item_t *cbor_new_int8();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int8(void);
/** Allocates new integer with 2B width
*
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-cbor_item_t *cbor_new_int16();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int16(void);
/** Allocates new integer with 4B width
*
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-cbor_item_t *cbor_new_int32();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int32(void);
/** Allocates new integer with 8B width
*
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-cbor_item_t *cbor_new_int64();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int64(void);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_uint8(uint8_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint8(uint8_t value);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_uint16(uint16_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint16(uint16_t value);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_uint32(uint32_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint32(uint32_t value);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_uint64(uint64_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint64(uint64_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_negint8(uint8_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint8(uint8_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_negint16(uint16_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint16(uint16_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_negint32(uint32_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint32(uint32_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-cbor_item_t *cbor_build_negint64(uint64_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint64(uint64_t value);
#ifdef __cplusplus
}
#include "internal/memory_utils.h"
size_t cbor_map_size(const cbor_item_t *item) {
- assert(cbor_isa_map(item));
+ CBOR_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));
+ CBOR_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));
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
return item;
}
-cbor_item_t *cbor_new_indefinite_map() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_map(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
}
bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
struct _cbor_map_metadata *metadata =
(struct _cbor_map_metadata *)&item->metadata;
if (cbor_map_is_definite(item)) {
if (metadata->end_ptr >= metadata->allocated) {
/* Exponential realloc */
// Check for overflows first
- // TODO: Explicitly test this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
return false;
}
}
bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
- assert(cbor_isa_map(item));
+ CBOR_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)
}
bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
- assert(cbor_isa_map(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_map(item));
return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE;
}
}
struct cbor_pair *cbor_map_handle(const cbor_item_t *item) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
return (struct cbor_pair *)item->data;
}
#ifndef LIBCBOR_MAPS_H
#define LIBCBOR_MAPS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @param item[borrow] A map
* @return The number of pairs
*/
-size_t cbor_map_size(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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.
+ * @return **new** indefinite map. `NULL` on malloc failure.
*/
-cbor_item_t *cbor_new_indefinite_map();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_indefinite_map(void);
/** Add a pair to the map
*
* @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
+ * preallocated storage is full
*/
-bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_map_add(cbor_item_t *item,
+ struct cbor_pair pair);
/** Add a key to the map
*
* @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
+ * preallocated storage is full
*/
-bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key);
+_CBOR_NODISCARD CBOR_EXPORT bool _cbor_map_add_key(cbor_item_t *item,
+ cbor_item_t *key);
/** Add a value to the map
*
* @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
+ * preallocated storage is full
*/
-bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_map_is_indefinite(
+ const cbor_item_t *item);
/** Get the pairs storage
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT struct cbor_pair *cbor_map_handle(
+ const cbor_item_t *item);
#ifdef __cplusplus
}
size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
+ // cppcheck-suppress missingReturn
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return cbor_serialize_uint(item, buffer, buffer_size);
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;
- }
+/** Largest integer that can be encoded as embedded in the item leading byte. */
+const uint64_t kMaxEmbeddedInt = 23;
- size_t written;
+/** How many bytes will a tag for a nested item of a given `size` take when
+ * encoded.*/
+size_t _cbor_encoded_header_size(uint64_t size) {
+ if (size <= kMaxEmbeddedInt)
+ return 1;
+ else if (size <= UINT8_MAX)
+ return 2;
+ else if (size <= UINT16_MAX)
+ return 3;
+ else if (size <= UINT32_MAX)
+ return 5;
+ else
+ return 9;
+}
- /* 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;
+size_t cbor_serialized_size(const cbor_item_t *item) {
+ // cppcheck-suppress missingReturn
+ switch (cbor_typeof(item)) {
+ case CBOR_TYPE_UINT:
+ case CBOR_TYPE_NEGINT:
+ switch (cbor_int_get_width(item)) {
+ case CBOR_INT_8:
+ if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;
+ return 2;
+ case CBOR_INT_16:
+ return 3;
+ case CBOR_INT_32:
+ return 5;
+ case CBOR_INT_64:
+ return 9;
+ }
+ // Note: We do not _cbor_safe_signaling_add zero-length definite strings,
+ // they would cause zeroes to propagate. All other items are at least one
+ // byte.
+ case CBOR_TYPE_BYTESTRING: {
+ if (cbor_bytestring_is_definite(item)) {
+ size_t header_size =
+ _cbor_encoded_header_size(cbor_bytestring_length(item));
+ if (cbor_bytestring_length(item) == 0) return header_size;
+ return _cbor_safe_signaling_add(header_size,
+ cbor_bytestring_length(item));
+ }
+ size_t indef_bytestring_size = 2; // Leading byte + break
+ cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
+ for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
+ indef_bytestring_size = _cbor_safe_signaling_add(
+ indef_bytestring_size, cbor_serialized_size(chunks[i]));
+ }
+ return indef_bytestring_size;
}
-
- tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2);
-
- if (tmp_bfr == NULL) {
- _CBOR_FREE(bfr);
- return 0;
+ case CBOR_TYPE_STRING: {
+ if (cbor_string_is_definite(item)) {
+ size_t header_size =
+ _cbor_encoded_header_size(cbor_string_length(item));
+ if (cbor_string_length(item) == 0) return header_size;
+ return _cbor_safe_signaling_add(header_size, cbor_string_length(item));
+ }
+ size_t indef_string_size = 2; // Leading byte + break
+ cbor_item_t **chunks = cbor_string_chunks_handle(item);
+ for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
+ indef_string_size = _cbor_safe_signaling_add(
+ indef_string_size, cbor_serialized_size(chunks[i]));
+ }
+ return indef_string_size;
+ }
+ case CBOR_TYPE_ARRAY: {
+ size_t array_size = cbor_array_is_definite(item)
+ ? _cbor_encoded_header_size(cbor_array_size(item))
+ : 2; // Leading byte + break
+ cbor_item_t **items = cbor_array_handle(item);
+ for (size_t i = 0; i < cbor_array_size(item); i++) {
+ array_size = _cbor_safe_signaling_add(array_size,
+ cbor_serialized_size(items[i]));
+ }
+ return array_size;
+ }
+ case CBOR_TYPE_MAP: {
+ size_t map_size = cbor_map_is_definite(item)
+ ? _cbor_encoded_header_size(cbor_map_size(item))
+ : 2; // Leading byte + break
+ struct cbor_pair *items = cbor_map_handle(item);
+ for (size_t i = 0; i < cbor_map_size(item); i++) {
+ map_size = _cbor_safe_signaling_add(
+ map_size,
+ _cbor_safe_signaling_add(cbor_serialized_size(items[i].key),
+ cbor_serialized_size(items[i].value)));
+ }
+ return map_size;
}
- bfr = tmp_bfr;
+ case CBOR_TYPE_TAG: {
+ return _cbor_safe_signaling_add(
+ _cbor_encoded_header_size(cbor_tag_value(item)),
+ cbor_serialized_size(cbor_move(cbor_tag_item(item))));
+ }
+ case CBOR_TYPE_FLOAT_CTRL:
+ switch (cbor_float_get_width(item)) {
+ case CBOR_FLOAT_0:
+ return _cbor_encoded_header_size(cbor_ctrl_value(item));
+ case CBOR_FLOAT_16:
+ return 3;
+ case CBOR_FLOAT_32:
+ return 5;
+ case CBOR_FLOAT_64:
+ return 9;
+ }
+ }
+}
+
+size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
+ size_t *buffer_size) {
+ *buffer = NULL;
+ size_t serialized_size = cbor_serialized_size(item);
+ if (serialized_size == 0) {
+ if (buffer_size != NULL) *buffer_size = 0;
+ return 0;
+ }
+ *buffer = _cbor_malloc(serialized_size);
+ if (*buffer == NULL) {
+ if (buffer_size != NULL) *buffer_size = 0;
+ return 0;
}
- *buffer = bfr;
- *buffer_size = bfr_size;
+
+ size_t written = cbor_serialize(item, *buffer, serialized_size);
+ CBOR_ASSERT(written == serialized_size);
+ if (buffer_size != NULL) *buffer_size = serialized_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));
+ CBOR_ASSERT(cbor_isa_uint(item));
+ // cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
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));
+ CBOR_ASSERT(cbor_isa_negint(item));
+ // cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
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));
+ CBOR_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)) {
+ if (written > 0 && (buffer_size - written >= length)) {
memcpy(buffer + written, cbor_bytestring_handle(item), length);
return written + length;
- } else
- return 0;
+ }
+ return 0;
} else {
- assert(cbor_bytestring_is_indefinite(item));
+ CBOR_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 (chunk_written == 0) return 0;
+ written += chunk_written;
}
- if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
- return written + 1;
- else
- return 0;
+
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_string(item));
+ CBOR_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;
+ }
+ return 0;
} else {
- assert(cbor_string_is_indefinite(item));
+ CBOR_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 (chunk_written == 0) return 0;
+ written += chunk_written;
}
- if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
- return written + 1;
- else
- return 0;
+
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_array(item));
+ CBOR_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));
+ CBOR_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 =
+ size_t item_written =
cbor_serialize(*(handle++), buffer + written, buffer_size - written);
- if (item_written == 0)
- return 0;
- else
- written += item_written;
+ if (item_written == 0) return 0;
+ 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;
+ CBOR_ASSERT(cbor_array_is_indefinite(item));
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_map(item));
+ CBOR_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));
+ CBOR_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 =
+ size_t item_written =
cbor_serialize(handle->key, buffer + written, buffer_size - written);
- if (item_written == 0)
+ if (item_written == 0) {
return 0;
- else
- written += item_written;
+ }
+ 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 (item_written == 0) return 0;
+ 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;
+ CBOR_ASSERT(cbor_map_is_indefinite(item));
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_tag(item));
+ CBOR_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 item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),
+ buffer + written, buffer_size - written);
+ if (item_written == 0) return 0;
+ 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));
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ // cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
/* CTRL - special treatment */
return cbor_encode_double(cbor_float_get_float8(item), buffer,
buffer_size);
}
-
- /* Should never happen - make the compiler happy */
- return 0;
}
#ifndef LIBCBOR_SERIALIZATION_H
#define LIBCBOR_SERIALIZATION_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize(const cbor_item_t *item,
+ cbor_mutable_data buffer,
+ size_t buffer_size);
+
+/** Compute the length (in bytes) of the item when serialized using
+ * `cbor_serialize`.
+ *
+ * Time complexity is proportional to the number of nested items.
+ *
+ * @param item[borrow] A data item
+ * @return Length (>= 1) of the item when serialized. 0 if the length overflows
+ * `size_t`.
+ */
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_serialized_size(const cbor_item_t *item);
/** Serialize the given item, allocating buffers as needed
+ *
+ * Since libcbor v0.10, the return value is always the same as `buffer_size` (if
+ * provided, see https://github.com/PJK/libcbor/pull/251/). New clients should
+ * ignore the return value.
*
* \rst
- * .. warning:: It is your responsibility to free the buffer using an
- * appropriate ``free`` implementation. \endrst
+ * .. warning:: It is the caller's 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
+ * @param buffer_size[out] Size of the \p buffer, or ``NULL``
* @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);
+CBOR_EXPORT size_t cbor_serialize_alloc(const cbor_item_t *item,
+ cbor_mutable_data *buffer,
+ size_t *buffer_size);
/** Serialize an uint
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_uint(const cbor_item_t *,
+ cbor_mutable_data,
+ size_t);
/** Serialize a negint
*
- * @param item[borrow] A neging
+ * @param item[borrow] A negint
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_negint(const cbor_item_t *,
+ cbor_mutable_data,
+ size_t);
/** Serialize a bytestring
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_serialize_bytestring(const cbor_item_t *, cbor_mutable_data, size_t);
/** Serialize a string
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_string(const cbor_item_t *,
+ cbor_mutable_data,
+ size_t);
/** Serialize an array
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_array(const cbor_item_t *,
+ cbor_mutable_data,
+ size_t);
/** Serialize a map
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_map(const cbor_item_t *,
+ cbor_mutable_data,
+ size_t);
/** Serialize a tag
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_tag(const cbor_item_t *,
+ cbor_mutable_data,
+ size_t);
/** Serialize a
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_serialize_float_ctrl(const cbor_item_t *, cbor_mutable_data, size_t);
#ifdef __cplusplus
}
#include "streaming.h"
#include "internal/loaders.h"
-bool static _cbor_claim_bytes(size_t required, size_t provided,
- struct cbor_decoder_result *result) {
+static bool 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->required = required + result->read;
result->read = 0;
result->status = CBOR_DECODER_NEDATA;
- result->required = required;
return false;
} else {
result->read += required;
}
}
+// Use implicit capture as an exception to avoid the super long parameter list
+#define CLAIM_BYTES_AND_INVOKE(callback_name, length, source_extra_offset) \
+ do { \
+ if (claim_bytes(length, source_size, &result)) { \
+ callbacks->callback_name(context, source + 1 + source_extra_offset, \
+ length); \
+ } \
+ } while (0)
+
+#define READ_CLAIM_INVOKE(callback_name, length_reader, length_bytes) \
+ do { \
+ if (claim_bytes(length_bytes, source_size, &result)) { \
+ uint64_t length = length_reader(source + 1); \
+ CLAIM_BYTES_AND_INVOKE(callback_name, length, length_bytes); \
+ } \
+ return result; \
+ } while (0)
+
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};
+ // Attempt to claim the initial MTB byte
+ struct cbor_decoder_result result = {.status = CBOR_DECODER_FINISHED};
+ if (!claim_bytes(1, source_size, &result)) {
+ return result;
}
- /* 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 0x18:
/* One byte unsigned integer */
{
- if (_cbor_claim_bytes(1, source_size, &result)) {
+ if (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)) {
+ if (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)) {
+ if (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)) {
+ if (claim_bytes(8, source_size, &result)) {
callbacks->uint64(context, _cbor_load_uint64(source + 1));
}
return result;
case 0x1E: /* Fallthrough */
case 0x1F:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x20: /* Fallthrough */
case 0x21: /* Fallthrough */
case 0x22: /* Fallthrough */
case 0x38:
/* One byte negative integer */
{
- if (_cbor_claim_bytes(1, source_size, &result)) {
+ if (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)) {
+ if (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)) {
+ if (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)) {
+ if (claim_bytes(8, source_size, &result)) {
callbacks->negint64(context, _cbor_load_uint64(source + 1));
}
return result;
case 0x3E: /* Fallthrough */
case 0x3F:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x40: /* Fallthrough */
case 0x41: /* Fallthrough */
case 0x42: /* 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);
- }
+ uint64_t length = _cbor_load_uint8(source) - 0x40; /* 0x40 offset */
+ CLAIM_BYTES_AND_INVOKE(byte_string, length, 0);
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;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint8, 1);
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;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint16, 2);
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;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint32, 4);
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;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint64, 8);
case 0x5C: /* Fallthrough */
case 0x5D: /* Fallthrough */
case 0x5E:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x5F:
/* Indefinite byte string */
{
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);
- }
+ uint64_t length = _cbor_load_uint8(source) - 0x60; /* 0x60 offset */
+ CLAIM_BYTES_AND_INVOKE(string, length, 0);
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;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint8, 1);
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;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint16, 2);
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;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint32, 4);
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;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint64, 8);
case 0x7C: /* Fallthrough */
case 0x7D: /* Fallthrough */
case 0x7E:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x7F:
/* Indefinite length string */
{
/* Embedded one byte length array */
{
callbacks->array_start(
- context, (size_t)_cbor_load_uint8(source) - 0x80); /* 0x40 offset */
+ context, _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));
+ if (claim_bytes(1, source_size, &result)) {
+ callbacks->array_start(context, _cbor_load_uint8(source + 1));
}
return result;
}
case 0x99:
/* Two bytes length array */
{
- if (_cbor_claim_bytes(2, source_size, &result)) {
- callbacks->array_start(context,
- (size_t)_cbor_load_uint16(source + 1));
+ if (claim_bytes(2, source_size, &result)) {
+ callbacks->array_start(context, _cbor_load_uint16(source + 1));
}
return result;
}
case 0x9A:
/* Four bytes length array */
{
- if (_cbor_claim_bytes(4, source_size, &result)) {
- callbacks->array_start(context,
- (size_t)_cbor_load_uint32(source + 1));
+ if (claim_bytes(4, source_size, &result)) {
+ callbacks->array_start(context, _cbor_load_uint32(source + 1));
}
return result;
}
case 0x9B:
/* Eight bytes length array */
{
- if (_cbor_claim_bytes(8, source_size, &result)) {
- callbacks->array_start(context,
- (size_t)_cbor_load_uint64(source + 1));
+ if (claim_bytes(8, source_size, &result)) {
+ callbacks->array_start(context, _cbor_load_uint64(source + 1));
}
return result;
}
case 0x9D: /* Fallthrough */
case 0x9E:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x9F:
/* Indefinite length array */
{
case 0xB7:
/* Embedded one byte length map */
{
- callbacks->map_start(
- context, (size_t)_cbor_load_uint8(source) - 0xA0); /* 0xA0 offset */
+ callbacks->map_start(context,
+ _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));
+ if (claim_bytes(1, source_size, &result)) {
+ callbacks->map_start(context, _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));
+ if (claim_bytes(2, source_size, &result)) {
+ callbacks->map_start(context, _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));
+ if (claim_bytes(4, source_size, &result)) {
+ callbacks->map_start(context, _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));
+ if (claim_bytes(8, source_size, &result)) {
+ callbacks->map_start(context, _cbor_load_uint64(source + 1));
}
return result;
}
case 0xBD: /* Fallthrough */
case 0xBE:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0xBF:
/* Indefinite length map */
{
case 0xC5:
/* Big float */
{
- callbacks->tag(context,
- _cbor_load_uint8(source) - 0xC0); /* 0xC0 offset */
+ callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) -
+ 0xC0)); /* 0xC0 offset */
return result;
}
case 0xC6: /* Fallthrough */
case 0xD3: /* Fallthrough */
case 0xD4: /* Unassigned tag value */
{
- return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR};
+ return (struct cbor_decoder_result){.status = 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 */
+ callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) -
+ 0xC0)); /* 0xC0 offset */
return result;
}
case 0xD8: /* 1B tag */
{
- if (_cbor_claim_bytes(1, source_size, &result)) {
+ if (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)) {
+ if (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)) {
+ if (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)) {
+ if (claim_bytes(8, source_size, &result)) {
callbacks->tag(context, _cbor_load_uint64(source + 1));
}
return result;
case 0xDE: /* Fallthrough */
case 0xDF: /* Reserved */
{
- return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR};
+ return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
}
case 0xE0: /* Fallthrough */
case 0xE1: /* Fallthrough */
case 0xF2: /* Fallthrough */
case 0xF3: /* Simple value - unassigned */
{
- return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR};
+ return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
}
case 0xF4:
/* False */
}
case 0xF8:
/* 1B simple value, unassigned */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0xF9:
/* 2B float */
{
- if (_cbor_claim_bytes(2, source_size, &result)) {
+ if (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)) {
+ if (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)) {
+ if (claim_bytes(8, source_size, &result)) {
callbacks->float8(context, _cbor_load_double(source + 1));
}
return result;
case 0xFD: /* Fallthrough */
case 0xFE:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0xFF:
/* Break */
- {
- callbacks->indef_break(context);
- return result;
- }
- default: /* Never happens - this shuts up the compiler */
- {
+ callbacks->indef_break(context);
+ // Never happens, the switch statement is exhaustive on the 1B range; make
+ // compiler happy
+ default:
return result;
- }
}
}
#define LIBCBOR_STREAMING_H
#include "callbacks.h"
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
/** Stateless decoder
*
- * Will try parsing the \p buffer and will invoke the appropriate callback on
+ * Will try parsing the \p source 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 source Input buffer
+ * @param source_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,
+_CBOR_NODISCARD CBOR_EXPORT struct cbor_decoder_result cbor_stream_decode(
+ cbor_data source, size_t source_size,
const struct cbor_callbacks* callbacks, void* context);
#ifdef __cplusplus
#include <string.h>
#include "internal/memory_utils.h"
-cbor_item_t *cbor_new_definite_string() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_definite_string(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
.refcount = 1,
return item;
}
-cbor_item_t *cbor_new_indefinite_string() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_string(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*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))};
+ .data = _cbor_malloc(sizeof(struct cbor_indefinite_string_data))};
_CBOR_DEPENDENT_NOTNULL(item, item->data);
*((struct cbor_indefinite_string_data *)item->data) =
(struct cbor_indefinite_string_data){
cbor_item_t *item = cbor_new_definite_string();
_CBOR_NOTNULL(item);
size_t len = strlen(val);
- unsigned char *handle = _CBOR_MALLOC(len);
+ unsigned char *handle = _cbor_malloc(len);
_CBOR_DEPENDENT_NOTNULL(item, handle);
memcpy(handle, val, len);
cbor_string_set_handle(item, handle, len);
cbor_item_t *cbor_build_stringn(const char *val, size_t length) {
cbor_item_t *item = cbor_new_definite_string();
_CBOR_NOTNULL(item);
- unsigned char *handle = _CBOR_MALLOC(length);
+ unsigned char *handle = _cbor_malloc(length);
_CBOR_DEPENDENT_NOTNULL(item, handle);
memcpy(handle, val, length);
cbor_string_set_handle(item, handle, length);
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));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_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) {
- // TODO: Add a test for this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) {
return false;
}
}
size_t cbor_string_length(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_string(item));
return item->data;
}
size_t cbor_string_codepoint_count(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
+ CBOR_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));
+ CBOR_ASSERT(cbor_isa_string(item));
return item->metadata.string_metadata.type == _CBOR_METADATA_DEFINITE;
}
#ifndef LIBCBOR_STRINGS_H
#define LIBCBOR_STRINGS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* ============================================================================
*/
-/** Returns the length of the underlying string
+/** Returns the length of the underlying string in bytes
*
- * For definite strings only
+ * There can be fewer unicode character than bytes (see
+ * `cbor_string_codepoint_count`). 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);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_string_length(const cbor_item_t *item);
/** The number of codepoints in this string
*
* @param item[borrow] A string
* @return The number of codepoints in this string
*/
-size_t cbor_string_codepoint_count(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_string_is_indefinite(
+ const cbor_item_t *item);
/** Get the handle to the underlying 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);
+_CBOR_NODISCARD CBOR_EXPORT 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
+ * 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);
+CBOR_EXPORT 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
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_string_chunk_count(const cbor_item_t *item);
/** Appends a chunk to the 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);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_string_add_chunk(cbor_item_t *item,
+ cbor_item_t *chunk);
/** Creates a new definite string
*
*
* @return **new** definite string. `NULL` on malloc failure.
*/
-cbor_item_t *cbor_new_definite_string();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_definite_string(void);
/** Creates a new indefinite string
*
*
* @return **new** indefinite string. `NULL` on malloc failure.
*/
-cbor_item_t *cbor_new_indefinite_string();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_indefinite_string(void);
/** Creates a new string and initializes it
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_string(const char *val);
/** Creates a new string and initializes it
*
* @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);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_stringn(const char *val,
+ size_t length);
#ifdef __cplusplus
}
#include "tags.h"
cbor_item_t *cbor_new_tag(uint64_t value) {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
}
cbor_item_t *cbor_tag_item(const cbor_item_t *item) {
- assert(cbor_isa_tag(item));
- return item->metadata.tag_metadata.tagged_item;
+ CBOR_ASSERT(cbor_isa_tag(item));
+ return cbor_incref(item->metadata.tag_metadata.tagged_item);
}
uint64_t cbor_tag_value(const cbor_item_t *item) {
- assert(cbor_isa_tag(item));
+ CBOR_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_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);
+ if (res == NULL) {
+ return NULL;
+ }
cbor_tag_set_item(res, item);
return res;
}
#ifndef LIBCBOR_TAGS_H
#define LIBCBOR_TAGS_H
+#include "cbor/cbor_export.h"
#include "cbor/common.h"
#ifdef __cplusplus
* @return **new** tag. Item reference is `NULL`. Returns `NULL` upon
* memory allocation failure
*/
-cbor_item_t *cbor_new_tag(uint64_t value);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+_CBOR_NODISCARD CBOR_EXPORT 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);
+CBOR_EXPORT void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item);
/** Build a new tag
*
* @param value Tag value
* @return **new** tag item
*/
-cbor_item_t *cbor_build_tag(uint64_t value, cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_tag(uint64_t value,
+ cbor_item_t *item);
#ifdef __cplusplus
}