/*1* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>2*3* libcbor is free software; you can redistribute it and/or modify4* it under the terms of the MIT license. See LICENSE for details.5*/67#ifndef LIBCBOR_COMMON_H8#define LIBCBOR_COMMON_H910#include <assert.h>11#include <stdbool.h>12#include <stddef.h>13#include <stdint.h>14#include <stdlib.h>1516#include "cbor/cbor_export.h"17#include "cbor/configuration.h"18#include "data.h"1920#ifdef __cplusplus21extern "C" {2223/**24* C99 is not a subset of C++ -- 'restrict' qualifier is not a part of the25* language. This is a workaround to keep it in C headers -- compilers allow26* linking non-restrict signatures with restrict implementations.27*28* If you know a nicer way, please do let me know.29*/30#define CBOR_RESTRICT_POINTER3132#else3334// MSVC + C++ workaround35#define CBOR_RESTRICT_POINTER CBOR_RESTRICT_SPECIFIER3637#endif3839static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION;40static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION;41static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;4243#define CBOR_VERSION \44_CBOR_TO_STR(CBOR_MAJOR_VERSION) \45"." _CBOR_TO_STR(CBOR_MINOR_VERSION) "." _CBOR_TO_STR(CBOR_PATCH_VERSION)46#define CBOR_HEX_VERSION \47((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)4849/* http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing50*/51#ifdef DEBUG52#include <stdio.h>53#define _cbor_debug_print(fmt, ...) \54do { \55if (DEBUG) \56fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \57__VA_ARGS__); \58} while (0)59extern bool _cbor_enable_assert;60// Like `assert`, but can be dynamically disabled in tests to allow testing61// invalid behaviors.62#define CBOR_ASSERT(e) assert(!_cbor_enable_assert || (e))63#define _CBOR_TEST_DISABLE_ASSERT(block) \64do { \65_cbor_enable_assert = false; \66block _cbor_enable_assert = true; \67} while (0)68#else69#define debug_print(fmt, ...) \70do { \71} while (0)72#define CBOR_ASSERT(e)73#define _CBOR_TEST_DISABLE_ASSERT(block) \74do { \75block \76} while (0)77#endif7879#define _CBOR_TO_STR_(x) #x80#define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */8182#ifdef __GNUC__83#define _CBOR_UNUSED(x) __attribute__((__unused__)) x84// TODO(https://github.com/PJK/libcbor/issues/247): Prefer [[nodiscard]] if85// available86#define _CBOR_NODISCARD __attribute__((warn_unused_result))87#elif defined(_MSC_VER)88#define _CBOR_UNUSED(x) __pragma(warning(suppress : 4100 4101)) x89#define _CBOR_NODISCARD90#else91#define _CBOR_UNUSED(x) x92#define _CBOR_NODISCARD93#endif9495typedef void *(*_cbor_malloc_t)(size_t);96typedef void *(*_cbor_realloc_t)(void *, size_t);97typedef void (*_cbor_free_t)(void *);9899CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc;100CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc;101CBOR_EXPORT extern _cbor_free_t _cbor_free;102103// Macro to short-circuit builder functions when memory allocation fails104#define _CBOR_NOTNULL(cbor_item) \105do { \106if (cbor_item == NULL) { \107return NULL; \108} \109} while (0)110111// Macro to short-circuit builders when memory allocation of nested data fails112#define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \113do { \114if (pointer == NULL) { \115_cbor_free(cbor_item); \116return NULL; \117} \118} while (0)119120/** Sets the memory management routines to use.121*122* By default, libcbor will use the standard library `malloc`, `realloc`, and123* `free`.124*125* \rst126* .. warning:: This function modifies the global state and should therefore be127* used accordingly. Changing the memory handlers while allocated items exist128* will result in a ``free``/``malloc`` mismatch. This function is not thread129* safe with respect to both itself and all the other *libcbor* functions that130* work with the heap.131*132* .. note:: `realloc` implementation must correctly support `NULL` reallocation133* (see e.g. http://en.cppreference.com/w/c/memory/realloc)134* \endrst135*136* @param custom_malloc malloc implementation137* @param custom_realloc realloc implementation138* @param custom_free free implementation139*/140CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc,141_cbor_realloc_t custom_realloc,142_cbor_free_t custom_free);143144/*145* ============================================================================146* Type manipulation147* ============================================================================148*/149150/** Get the type of the item151*152* @param item153* @return The type154*/155_CBOR_NODISCARD156CBOR_EXPORT cbor_type cbor_typeof(157const cbor_item_t *item); /* Will be inlined iff link-time opt is enabled */158159/* Standard CBOR Major item types */160161/** Does the item have the appropriate major type?162* @param item the item163* @return Is the item an #CBOR_TYPE_UINT?164*/165_CBOR_NODISCARD166CBOR_EXPORT bool cbor_isa_uint(const cbor_item_t *item);167168/** Does the item have the appropriate major type?169* @param item the item170* @return Is the item a #CBOR_TYPE_NEGINT?171*/172_CBOR_NODISCARD173CBOR_EXPORT bool cbor_isa_negint(const cbor_item_t *item);174175/** Does the item have the appropriate major type?176* @param item the item177* @return Is the item a #CBOR_TYPE_BYTESTRING?178*/179_CBOR_NODISCARD180CBOR_EXPORT bool cbor_isa_bytestring(const cbor_item_t *item);181182/** Does the item have the appropriate major type?183* @param item the item184* @return Is the item a #CBOR_TYPE_STRING?185*/186_CBOR_NODISCARD187CBOR_EXPORT bool cbor_isa_string(const cbor_item_t *item);188189/** Does the item have the appropriate major type?190* @param item the item191* @return Is the item an #CBOR_TYPE_ARRAY?192*/193_CBOR_NODISCARD194CBOR_EXPORT bool cbor_isa_array(const cbor_item_t *item);195196/** Does the item have the appropriate major type?197* @param item the item198* @return Is the item a #CBOR_TYPE_MAP?199*/200_CBOR_NODISCARD201CBOR_EXPORT bool cbor_isa_map(const cbor_item_t *item);202203/** Does the item have the appropriate major type?204* @param item the item205* @return Is the item a #CBOR_TYPE_TAG?206*/207_CBOR_NODISCARD208CBOR_EXPORT bool cbor_isa_tag(const cbor_item_t *item);209210/** Does the item have the appropriate major type?211* @param item the item212* @return Is the item a #CBOR_TYPE_FLOAT_CTRL?213*/214_CBOR_NODISCARD215CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t *item);216217/* Practical types with respect to their semantics (but not tag values) */218219/** Is the item an integer, either positive or negative?220* @param item the item221* @return Is the item an integer, either positive or negative?222*/223_CBOR_NODISCARD224CBOR_EXPORT bool cbor_is_int(const cbor_item_t *item);225226/** Is the item an a floating point number?227* @param item the item228* @return Is the item a floating point number?229*/230_CBOR_NODISCARD231CBOR_EXPORT bool cbor_is_float(const cbor_item_t *item);232233/** Is the item an a boolean?234* @param item the item235* @return Is the item a boolean?236*/237_CBOR_NODISCARD238CBOR_EXPORT bool cbor_is_bool(const cbor_item_t *item);239240/** Does this item represent `null`241*242* \rst243* .. warning:: This is in no way related to the value of the pointer. Passing a244* null pointer will most likely result in a crash.245* \endrst246*247* @param item the item248* @return Is the item (CBOR logical) null?249*/250_CBOR_NODISCARD251CBOR_EXPORT bool cbor_is_null(const cbor_item_t *item);252253/** Does this item represent `undefined`254*255* \rst256* .. warning:: Care must be taken to distinguish nulls and undefined values in257* C.258* \endrst259*260* @param item the item261* @return Is the item (CBOR logical) undefined?262*/263_CBOR_NODISCARD264CBOR_EXPORT bool cbor_is_undef(const cbor_item_t *item);265266/*267* ============================================================================268* Memory management269* ============================================================================270*/271272/** Increases the item's reference count by one273*274* Constant complexity; items referring to this one or items being referred to275* are not updated.276*277* This function can be used to extend reference counting to client code.278*279* @param item Reference to an item280* @return The input \p item281*/282CBOR_EXPORT cbor_item_t *cbor_incref(cbor_item_t *item);283284/** Decreases the item's reference count by one, deallocating the item if needed285*286* In case the item is deallocated, the reference count of all items this item287* references will also be #cbor_decref 'ed recursively.288*289* @param item Reference to an item. Will be set to `NULL` if deallocated290*/291CBOR_EXPORT void cbor_decref(cbor_item_t **item);292293/** Decreases the item's reference count by one, deallocating the item if needed294*295* Convenience wrapper for #cbor_decref when its set-to-null behavior is not296* needed297*298* @param item Reference to an item299*/300CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t *item);301302/** Get the item's reference count303*304* \rst305* .. warning:: This does *not* account for transitive references.306* \endrst307*308* @todo Add some inline examples for reference counting309*310* @param item the item311* @return the reference count312*/313_CBOR_NODISCARD314CBOR_EXPORT size_t cbor_refcount(const cbor_item_t *item);315316/** Provides CPP-like move construct317*318* Decreases the reference count by one, but does not deallocate the item even319* if its refcount reaches zero. This is useful for passing intermediate values320* to functions that increase reference count. Should only be used with321* functions that `incref` their arguments.322*323* \rst324* .. warning:: If the item is moved without correctly increasing the reference325* count afterwards, the memory will be leaked.326* \endrst327*328* @param item Reference to an item329* @return the item with reference count decreased by one330*/331_CBOR_NODISCARD332CBOR_EXPORT cbor_item_t *cbor_move(cbor_item_t *item);333334#ifdef __cplusplus335}336#endif337338#endif // LIBCBOR_COMMON_H339340341