update to upstream libcbor v.0.10.0 and crank major. Also includes
authordjm <djm@openbsd.org>
Sat, 31 Dec 2022 03:35:21 +0000 (03:35 +0000)
committerdjm <djm@openbsd.org>
Sat, 31 Dec 2022 03:35:21 +0000 (03:35 +0000)
e308674c5d to fix PR259. This release includes a number of memory
leak fixes.

Disable the upsteam custom allocators feature.

Feedback/ok tb@

Thanks also to Pedro Martelletto for pointing out the new release as
well as PR259.

47 files changed:
lib/libcbor/Makefile
lib/libcbor/README.md
lib/libcbor/README.openbsd
lib/libcbor/shlib_version
lib/libcbor/src/allocators.c
lib/libcbor/src/cbor.c
lib/libcbor/src/cbor.h
lib/libcbor/src/cbor/arrays.c
lib/libcbor/src/cbor/arrays.h
lib/libcbor/src/cbor/bytestrings.c
lib/libcbor/src/cbor/bytestrings.h
lib/libcbor/src/cbor/callbacks.c
lib/libcbor/src/cbor/callbacks.h
lib/libcbor/src/cbor/cbor_export.h [new file with mode: 0644]
lib/libcbor/src/cbor/common.c
lib/libcbor/src/cbor/common.h
lib/libcbor/src/cbor/configuration.h
lib/libcbor/src/cbor/configuration.h.in
lib/libcbor/src/cbor/data.h
lib/libcbor/src/cbor/encoding.c
lib/libcbor/src/cbor/encoding.h
lib/libcbor/src/cbor/floats_ctrls.c
lib/libcbor/src/cbor/floats_ctrls.h
lib/libcbor/src/cbor/internal/builder_callbacks.c
lib/libcbor/src/cbor/internal/builder_callbacks.h
lib/libcbor/src/cbor/internal/encoders.c
lib/libcbor/src/cbor/internal/encoders.h
lib/libcbor/src/cbor/internal/loaders.c
lib/libcbor/src/cbor/internal/loaders.h
lib/libcbor/src/cbor/internal/memory_utils.c
lib/libcbor/src/cbor/internal/memory_utils.h
lib/libcbor/src/cbor/internal/stack.c
lib/libcbor/src/cbor/internal/stack.h
lib/libcbor/src/cbor/internal/unicode.c
lib/libcbor/src/cbor/internal/unicode.h
lib/libcbor/src/cbor/ints.c
lib/libcbor/src/cbor/ints.h
lib/libcbor/src/cbor/maps.c
lib/libcbor/src/cbor/maps.h
lib/libcbor/src/cbor/serialization.c
lib/libcbor/src/cbor/serialization.h
lib/libcbor/src/cbor/streaming.c
lib/libcbor/src/cbor/streaming.h
lib/libcbor/src/cbor/strings.c
lib/libcbor/src/cbor/strings.h
lib/libcbor/src/cbor/tags.c
lib/libcbor/src/cbor/tags.h

index 204997c..561cba6 100644 (file)
@@ -1,8 +1,10 @@
-# $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
@@ -26,6 +28,8 @@ HDRS+=        cbor/arrays.h cbor/bytestrings.h cbor/callbacks.h cbor/common.h
 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=
 
index 0b89756..bd76243 100644 (file)
@@ -22,7 +22,7 @@ Get the latest documentation at [libcbor.readthedocs.org](http://libcbor.readthe
 
 ## 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)!
 
index add7f50..a811509 100644 (file)
@@ -1,4 +1,9 @@
-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.
index 1edea46..b52599a 100644 (file)
@@ -1,2 +1,2 @@
-major=1
+major=2
 minor=0
index 273e093..43c5440 100644 (file)
@@ -7,9 +7,9 @@
 
 #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) {
index 24e5aa3..626dddd 100644 (file)
@@ -82,10 +82,8 @@ cbor_item_t *cbor_load(cbor_data source, size_t source_size,
           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;
@@ -102,9 +100,7 @@ cbor_item_t *cbor_load(cbor_data source, size_t source_size,
     }
   } 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;
@@ -133,8 +129,6 @@ static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
     case CBOR_INT_64:
       res = cbor_build_uint64(cbor_get_uint64(item));
       break;
-    default:
-      return NULL;
   }
 
   if (negative) cbor_mark_negint(res);
@@ -143,6 +137,7 @@ static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
 }
 
 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));
@@ -153,11 +148,10 @@ static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *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);
@@ -169,10 +163,24 @@ cbor_item_t *cbor_copy(cbor_item_t *item) {
                                      cbor_bytestring_length(item));
       } else {
         cbor_item_t *res = cbor_new_indefinite_bytestring();
-        for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
-          cbor_bytestring_add_chunk(
-              res,
-              cbor_move(cbor_copy(cbor_bytestring_chunks_handle(item)[i])));
+        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:
@@ -181,45 +189,100 @@ cbor_item_t *cbor_copy(cbor_item_t *item) {
                                   cbor_string_length(item));
       } else {
         cbor_item_t *res = cbor_new_indefinite_string();
-        for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
-          cbor_string_add_chunk(
-              res, cbor_move(cbor_copy(cbor_string_chunks_handle(item)[i])));
+        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
@@ -246,13 +309,13 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
       fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
       fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
       break;
-    };
+    }
     case CBOR_TYPE_NEGINT: {
       fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " ");
       fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
       fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item));
       break;
-    };
+    }
     case CBOR_TYPE_BYTESTRING: {
       fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " ");
       if (cbor_bytestring_is_indefinite(item)) {
@@ -265,7 +328,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
         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)) {
@@ -286,7 +349,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
         fprintf(out, "\n");
       }
       break;
-    };
+    }
     case CBOR_TYPE_ARRAY: {
       fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " ");
       if (cbor_array_is_definite(item)) {
@@ -298,7 +361,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
       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)) {
@@ -312,13 +375,13 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
         _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)) {
@@ -335,7 +398,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
         fprintf(out, "value: %lf\n", cbor_float_get_float(item));
       }
       break;
-    };
+    }
   }
 }
 
index f4dfc9e..f386010 100644 (file)
@@ -20,6 +20,7 @@
 #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"
@@ -42,22 +43,22 @@ extern "C" {
  * @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
index c1d01af..a23bbe3 100644 (file)
 #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;
 }
 
@@ -31,9 +31,6 @@ bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value) {
   } 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) {
@@ -45,7 +42,7 @@ 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;
@@ -59,7 +56,6 @@ bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
     /* 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;
       }
@@ -84,22 +80,22 @@ bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
 }
 
 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);
@@ -119,8 +115,8 @@ cbor_item_t *cbor_new_definite_array(size_t size) {
   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){
index 3851975..cc5a7c0 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_ARRAYS_H
 #define LIBCBOR_ARRAYS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -19,14 +20,16 @@ extern "C" {
  * @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
  *
@@ -34,18 +37,22 @@ size_t cbor_array_allocated(const cbor_item_t* item);
  * @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
  *
@@ -56,21 +63,25 @@ bool cbor_array_set(cbor_item_t* item, size_t index, cbor_item_t* value);
  * @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
  *
@@ -80,31 +91,35 @@ bool cbor_array_is_indefinite(const cbor_item_t* item);
  * @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
 }
index 75a737b..5289371 100644 (file)
 #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;
 }
 
@@ -28,25 +28,26 @@ bool cbor_bytestring_is_indefinite(const cbor_item_t *item) {
   return !cbor_bytestring_is_definite(item);
 }
 
-cbor_item_t *cbor_new_definite_bytestring() {
-  cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+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){
@@ -60,7 +61,7 @@ cbor_item_t *cbor_new_indefinite_bytestring() {
 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);
@@ -70,31 +71,32 @@ cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t 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;
     }
index 9f9322c..fecaee9 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_BYTESTRINGS_H
 #define LIBCBOR_BYTESTRINGS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -27,21 +28,24 @@ extern "C" {
  * @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
  *
@@ -52,7 +56,8 @@ bool cbor_bytestring_is_indefinite(const cbor_item_t *item);
  * @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
  *
@@ -61,9 +66,9 @@ cbor_mutable_data cbor_bytestring_handle(const cbor_item_t *item);
  * 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
  *
@@ -73,14 +78,17 @@ void cbor_bytestring_set_handle(cbor_item_t *item,
  * @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
  *
@@ -93,7 +101,9 @@ size_t cbor_bytestring_chunk_count(const cbor_item_t *item);
  * @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
  *
@@ -101,15 +111,17 @@ bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk);
  *
  * @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
  *
@@ -120,7 +132,8 @@ cbor_item_t *cbor_new_indefinite_bytestring();
  * @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
 }
index 7d0f1c6..bdf3f79 100644 (file)
 
 #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,
 };
index 1d37f3e..c7ae205 100644 (file)
@@ -8,6 +8,9 @@
 #ifndef LIBCBOR_CALLBACKS_H
 #define LIBCBOR_CALLBACKS_H
 
+#include <stdint.h>
+
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -30,10 +33,10 @@ typedef void (*cbor_int64_callback)(void *, uint64_t);
 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);
@@ -105,79 +108,79 @@ struct cbor_callbacks {
 };
 
 /** 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
 }
diff --git a/lib/libcbor/src/cbor/cbor_export.h b/lib/libcbor/src/cbor/cbor_export.h
new file mode 100644 (file)
index 0000000..de54974
--- /dev/null
@@ -0,0 +1,42 @@
+
+#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 */
index 7ccce38..efbd37e 100644 (file)
 #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;
 }
@@ -78,7 +82,7 @@ cbor_item_t *cbor_incref(cbor_item_t *item) {
 
 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:
@@ -88,29 +92,29 @@ void cbor_decref(cbor_item_t **item_ref) {
         { 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;
       }
@@ -120,7 +124,7 @@ void cbor_decref(cbor_item_t **item_ref) {
         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: {
@@ -130,13 +134,13 @@ void cbor_decref(cbor_item_t **item_ref) {
           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: {
@@ -144,8 +148,7 @@ void cbor_decref(cbor_item_t **item_ref) {
         break;
       }
     }
-    _CBOR_FREE(item);
-    // TODO
+    _cbor_free(item);
     *item_ref = NULL;
   }
 }
index d54a23c..6a6f969 100644 (file)
@@ -13,6 +13,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include "cbor/cbor_export.h"
 #include "cbor/configuration.h"
 #include "data.h"
 
@@ -20,7 +21,7 @@
 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.
  *
@@ -39,9 +40,9 @@ static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION;
 static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION;
 static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
 
-#define CBOR_VERSION         \
-  TO_STR(CBOR_MAJOR_VERSION) \
-  "." TO_STR(CBOR_MINOR_VERSION) "." TO_STR(CBOR_PATCH_VERSION)
+#define CBOR_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)
 
@@ -49,20 +50,57 @@ static const uint8_t cbor_patch_version = 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) \
@@ -76,51 +114,32 @@ static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
 #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
 
 /*
@@ -134,7 +153,8 @@ void cbor_set_allocs(_cbor_malloc_t custom_malloc,
  * @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 */
@@ -143,49 +163,57 @@ cbor_type cbor_typeof(
  * @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) */
 
@@ -193,37 +221,48 @@ bool cbor_isa_float_ctrl(const cbor_item_t *item);
  * @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);
 
 /*
  * ============================================================================
@@ -238,7 +277,7 @@ 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
  *
@@ -247,7 +286,7 @@ cbor_item_t *cbor_incref(cbor_item_t *item);
  *
  * @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
  *
@@ -256,7 +295,7 @@ void cbor_decref(cbor_item_t **item);
  *
  * @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
  *
@@ -267,7 +306,8 @@ void cbor_intermediate_decref(cbor_item_t *item);
  * @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
  *
@@ -278,12 +318,14 @@ size_t cbor_refcount(const cbor_item_t *item);
  *
  * \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
 }
index 8e4e3be..d4ea06e 100644 (file)
@@ -2,10 +2,9 @@
 #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
index 6f65980..0052a15 100644 (file)
@@ -5,7 +5,6 @@
 #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
index 8dbf248..a12e92f 100644 (file)
@@ -45,6 +45,8 @@ typedef enum {
   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? */
@@ -86,6 +88,11 @@ typedef enum {
   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;
@@ -199,29 +206,54 @@ struct cbor_pair {
 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;
 };
 
index 1928152..9d931d1 100644 (file)
@@ -135,17 +135,23 @@ size_t cbor_encode_half(float value, unsigned char *buffer,
       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) {
@@ -158,7 +164,9 @@ size_t cbor_encode_half(float value, unsigned char *buffer,
          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) |
index 34a7382..bcc04f8 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_ENCODING_H
 #define LIBCBOR_ENCODING_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -15,54 +16,87 @@ extern "C" {
 #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
  *
@@ -84,21 +118,20 @@ size_t cbor_encode_undef(unsigned char *, size_t);
  * 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
 }
index b7e5fce..57bf477 100644 (file)
 #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;
@@ -55,46 +56,45 @@ double cbor_float_get_float(const cbor_item_t *item) {
     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){
@@ -106,8 +106,8 @@ cbor_item_t *cbor_new_ctrl() {
   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){
@@ -118,8 +118,8 @@ cbor_item_t *cbor_new_float2() {
   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){
@@ -130,8 +130,8 @@ cbor_item_t *cbor_new_float4() {
   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){
@@ -142,14 +142,14 @@ cbor_item_t *cbor_new_float8() {
   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);
index 74dd97f..7065536 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_FLOATS_CTRLS_H
 #define LIBCBOR_FLOATS_CTRLS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -25,14 +26,16 @@ extern "C" {
  * @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
  *
@@ -41,16 +44,18 @@ cbor_float_width cbor_float_get_width(const cbor_item_t *item);
  * @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
  *
@@ -59,7 +64,8 @@ float cbor_float_get_float4(const cbor_item_t *item);
  * @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
  *
@@ -68,14 +74,15 @@ double cbor_float_get_float8(const cbor_item_t *item);
  * @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
  *
@@ -83,7 +90,7 @@ bool cbor_get_bool(const cbor_item_t *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
  *
@@ -91,7 +98,7 @@ cbor_item_t *cbor_new_ctrl();
  *
  * @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
  *
@@ -99,7 +106,7 @@ cbor_item_t *cbor_new_float2();
  *
  * @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
  *
@@ -107,102 +114,102 @@ cbor_item_t *cbor_new_float4();
  *
  * @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
 }
index f6c5711..78277f0 100644 (file)
@@ -6,9 +6,12 @@
  */
 
 #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;
     }
   }
 }
@@ -95,6 +121,16 @@ void _cbor_builder_append(cbor_item_t *item,
     }                              \
   } 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) { \
@@ -151,6 +187,7 @@ void cbor_builder_negint8_callback(void *context, uint8_t value) {
 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);
@@ -175,34 +212,36 @@ void cbor_builder_negint64_callback(void *context, uint64_t value) {
 }
 
 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);
   }
 }
 
@@ -214,19 +253,20 @@ void cbor_builder_byte_string_start_callback(void *context) {
 }
 
 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;
@@ -234,25 +274,25 @@ void cbor_builder_string_callback(void *context, cbor_data data,
   }
 
   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);
   }
 }
 
@@ -263,8 +303,9 @@ void cbor_builder_string_start_callback(void *context) {
   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) {
@@ -288,8 +329,9 @@ void cbor_builder_indef_map_start_callback(void *context) {
   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) {
@@ -305,14 +347,13 @@ void cbor_builder_map_start_callback(void *context, size_t size) {
 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;
   }
@@ -340,6 +381,7 @@ void cbor_builder_indef_break_callback(void *context) {
 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);
 }
index a93afb1..7893960 100644 (file)
@@ -26,6 +26,10 @@ struct _cbor_decoder_context {
   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);
@@ -42,19 +46,19 @@ void cbor_builder_negint32_callback(void *, uint32_t);
 
 void cbor_builder_negint64_callback(void *, uint64_t);
 
-void cbor_builder_string_callback(void *, cbor_data, size_t);
+void cbor_builder_string_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 *);
 
index 657e25c..49d4d7f 100644 (file)
@@ -33,8 +33,8 @@ size_t _cbor_encode_uint16(uint16_t value, unsigned char *buffer,
 #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;
@@ -50,10 +50,10 @@ size_t _cbor_encode_uint32(uint32_t value, unsigned char *buffer,
 #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;
@@ -69,14 +69,14 @@ size_t _cbor_encode_uint64(uint64_t value, unsigned char *buffer,
 #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;
index 14ad501..7eadb71 100644 (file)
 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);
 
index af00f13..c25c633 100644 (file)
@@ -64,7 +64,7 @@ float _cbor_decode_half(unsigned char *halfp) {
   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);
 }
index a4c82b2..ce37563 100644 (file)
@@ -15,18 +15,25 @@ extern "C" {
 #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
index 918b708..bbea63c 100644 (file)
@@ -23,12 +23,25 @@ size_t _cbor_highest_bit(size_t number) {
 }
 
 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;
   }
@@ -37,7 +50,7 @@ void* _cbor_alloc_multiple(size_t item_size, size_t item_count) {
 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;
   }
index c41ace6..14843c8 100644 (file)
 #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
index 79c9e5e..2db03cb 100644 (file)
@@ -7,14 +7,14 @@
 
 #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--;
 }
 
@@ -23,7 +23,7 @@ struct _cbor_stack_record *_cbor_stack_push(struct _cbor_stack *stack,
                                             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};
index 42ed044..cf2206b 100644 (file)
@@ -16,8 +16,18 @@ extern "C" {
 
 /** 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;
 };
 
@@ -27,10 +37,12 @@ struct _cbor_stack {
   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);
 
index 98b4972..1831c8e 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "unicode.h"
+#include <stdint.h>
 
 #define UTF8_ACCEPT 0
 #define UTF8_REJECT 1
@@ -65,12 +66,12 @@ uint32_t _cbor_unicode_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
   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]);
@@ -90,5 +91,5 @@ size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
 error:
   *status = (struct _cbor_unicode_status){.location = pos,
                                           .status = _CBOR_UNICODE_BADCP};
-  return -1;
+  return 0;
 }
index 5f64560..af32cc7 100644 (file)
@@ -19,11 +19,12 @@ enum _cbor_unicode_status_error { _CBOR_UNICODE_OK, _CBOR_UNICODE_BADCP };
 /** Signals unicode validation error and possibly its location */
 struct _cbor_unicode_status {
   enum _cbor_unicode_status_error status;
-  size_t location;
+  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
 }
index 880982e..b4d035a 100644 (file)
@@ -8,36 +8,37 @@
 #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);
@@ -48,46 +49,44 @@ uint64_t cbor_get_int(const cbor_item_t *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,
@@ -96,8 +95,8 @@ cbor_item_t *cbor_new_int8() {
   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,
@@ -106,8 +105,8 @@ cbor_item_t *cbor_new_int16() {
   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,
@@ -116,8 +115,8 @@ cbor_item_t *cbor_new_int32() {
   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,
index f965c29..9c1d572 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_INTS_H
 #define LIBCBOR_INTS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -25,35 +26,35 @@ extern "C" {
  * @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
  *
@@ -61,7 +62,7 @@ uint64_t cbor_get_int(const cbor_item_t *item);
  * @param value the value to assign. For negative integer, the logical value is
  * `-value - 1`
  */
-void cbor_set_uint8(cbor_item_t *item, uint8_t value);
+CBOR_EXPORT void cbor_set_uint8(cbor_item_t *item, uint8_t value);
 
 /** Assigns the integer value
  *
@@ -69,7 +70,7 @@ void cbor_set_uint8(cbor_item_t *item, uint8_t 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
  *
@@ -77,7 +78,7 @@ void cbor_set_uint16(cbor_item_t *item, uint16_t 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
  *
@@ -85,14 +86,15 @@ void cbor_set_uint32(cbor_item_t *item, uint32_t 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
  *
@@ -100,7 +102,7 @@ cbor_int_width cbor_int_get_width(const cbor_item_t *item);
  *
  * @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
  *
@@ -108,7 +110,7 @@ void cbor_mark_uint(cbor_item_t *item);
  *
  * @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
  *
@@ -117,7 +119,7 @@ void cbor_mark_negint(cbor_item_t *item);
  * @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
  *
@@ -126,7 +128,7 @@ cbor_item_t *cbor_new_int8();
  * @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
  *
@@ -135,7 +137,7 @@ cbor_item_t *cbor_new_int16();
  * @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
  *
@@ -144,63 +146,63 @@ cbor_item_t *cbor_new_int32();
  * @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
 }
index 45140e2..8711e57 100644 (file)
@@ -9,17 +9,17 @@
 #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){
@@ -34,8 +34,8 @@ cbor_item_t *cbor_new_definite_map(size_t size) {
   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){
@@ -50,7 +50,7 @@ cbor_item_t *cbor_new_indefinite_map() {
 }
 
 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)) {
@@ -66,7 +66,6 @@ bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
     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;
       }
@@ -94,7 +93,7 @@ bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
 }
 
 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)
@@ -105,13 +104,13 @@ bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
 }
 
 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;
 }
 
@@ -120,6 +119,6 @@ bool cbor_map_is_indefinite(const cbor_item_t *item) {
 }
 
 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;
 }
index 4e27eef..2c57412 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_MAPS_H
 #define LIBCBOR_MAPS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -25,28 +26,27 @@ extern "C" {
  * @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
  *
@@ -56,9 +56,10 @@ cbor_item_t *cbor_new_indefinite_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
  *
@@ -67,9 +68,10 @@ bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair);
  * @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
  *
@@ -78,23 +80,25 @@ bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key);
  * @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
  *
@@ -102,7 +106,8 @@ bool cbor_map_is_indefinite(const cbor_item_t *item);
  * @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
 }
index 41343ef..40f4c53 100644 (file)
@@ -19,6 +19,7 @@
 
 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);
@@ -36,44 +37,144 @@ size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
       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);
@@ -83,14 +184,13 @@ size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
       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);
@@ -100,173 +200,158 @@ size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
       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 */
@@ -280,7 +365,4 @@ size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
       return cbor_encode_double(cbor_float_get_float8(item), buffer,
                                 buffer_size);
   }
-
-  /* Should never happen - make the compiler happy */
-  return 0;
 }
index ef68cf8..a4921f9 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_SERIALIZATION_H
 #define LIBCBOR_SERIALIZATION_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -27,23 +28,42 @@ extern "C" {
  * @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
  *
@@ -52,16 +72,20 @@ size_t cbor_serialize_alloc(const cbor_item_t *item, cbor_mutable_data *buffer,
  * @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
  *
@@ -70,8 +94,8 @@ size_t cbor_serialize_negint(const cbor_item_t *, cbor_mutable_data, size_t);
  * @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
  *
@@ -80,7 +104,9 @@ size_t cbor_serialize_bytestring(const cbor_item_t *, cbor_mutable_data,
  * @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
  *
@@ -89,7 +115,9 @@ size_t cbor_serialize_string(const cbor_item_t *, cbor_mutable_data, size_t);
  * @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
  *
@@ -98,7 +126,9 @@ size_t cbor_serialize_array(const cbor_item_t *, cbor_mutable_data, size_t);
  * @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
  *
@@ -107,7 +137,9 @@ size_t cbor_serialize_map(const cbor_item_t *, cbor_mutable_data, size_t);
  * @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
  *
@@ -116,8 +148,8 @@ size_t cbor_serialize_tag(const cbor_item_t *, cbor_mutable_data, size_t);
  * @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
 }
index 9d85e15..922a71d 100644 (file)
@@ -8,13 +8,12 @@
 #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;
@@ -23,17 +22,33 @@ bool static _cbor_claim_bytes(size_t required, size_t provided,
   }
 }
 
+// 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 */
@@ -67,7 +82,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -75,7 +90,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -83,7 +98,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -91,7 +106,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -101,7 +116,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
@@ -135,7 +150,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -143,7 +158,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -151,7 +166,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -159,7 +174,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -169,7 +184,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
@@ -196,63 +211,27 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
       {
@@ -285,62 +264,27 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
       {
@@ -374,41 +318,38 @@ struct cbor_decoder_result cbor_stream_decode(
       /* 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;
       }
@@ -416,7 +357,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
       {
@@ -449,39 +390,39 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
       }
@@ -489,7 +430,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
       {
@@ -509,8 +450,8 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
@@ -529,40 +470,40 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -572,7 +513,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
@@ -595,7 +536,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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 */
@@ -623,11 +564,11 @@ struct cbor_decoder_result cbor_stream_decode(
       }
     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;
@@ -635,7 +576,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -643,7 +584,7 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
@@ -652,16 +593,13 @@ struct cbor_decoder_result cbor_stream_decode(
     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;
-    }
   }
 }
index d9d54b8..cb908e1 100644 (file)
@@ -9,6 +9,7 @@
 #define LIBCBOR_STREAMING_H
 
 #include "callbacks.h"
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -17,16 +18,16 @@ extern "C" {
 
 /** 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
index 209886b..de2d102 100644 (file)
@@ -9,8 +9,8 @@
 #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,
@@ -19,15 +19,15 @@ cbor_item_t *cbor_new_definite_string() {
   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){
@@ -42,7 +42,7 @@ cbor_item_t *cbor_build_string(const char *val) {
   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);
@@ -52,7 +52,7 @@ cbor_item_t *cbor_build_string(const char *val) {
 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);
@@ -62,31 +62,30 @@ cbor_item_t *cbor_build_stringn(const char *val, size_t 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;
     }
@@ -109,22 +108,22 @@ bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk) {
 }
 
 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;
 }
 
index 342d098..b9899c4 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_STRINGS_H
 #define LIBCBOR_STRINGS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -20,14 +21,15 @@ extern "C" {
  * ============================================================================
  */
 
-/** 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
  *
@@ -36,21 +38,24 @@ size_t cbor_string_length(const cbor_item_t *item);
  * @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
  *
@@ -61,24 +66,26 @@ bool cbor_string_is_indefinite(const cbor_item_t *item);
  * @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
  *
@@ -88,14 +95,16 @@ void cbor_string_set_handle(cbor_item_t *item,
  * @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
  *
@@ -108,7 +117,8 @@ size_t cbor_string_chunk_count(const cbor_item_t *item);
  * @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
  *
@@ -116,7 +126,7 @@ bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk);
  *
  * @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
  *
@@ -124,7 +134,7 @@ cbor_item_t *cbor_new_definite_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
  *
@@ -133,7 +143,7 @@ cbor_item_t *cbor_new_indefinite_string();
  * @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
  *
@@ -142,7 +152,8 @@ cbor_item_t *cbor_build_string(const char *val);
  * @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
 }
index 3853db4..3f3edb0 100644 (file)
@@ -8,7 +8,7 @@
 #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){
@@ -21,23 +21,26 @@ cbor_item_t *cbor_new_tag(uint64_t value) {
 }
 
 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;
 }
index 6e76c82..1fac44a 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef LIBCBOR_TAGS_H
 #define LIBCBOR_TAGS_H
 
+#include "cbor/cbor_export.h"
 #include "cbor/common.h"
 
 #ifdef __cplusplus
@@ -26,28 +27,28 @@ extern "C" {
  * @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
  *
@@ -55,7 +56,8 @@ void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item);
  * @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
 }