xref: /openbsd-src/lib/libcbor/src/cbor/common.h (revision 196a8b7f4cfc28ba67298490a91a38fd510e896c)
1da0d961cSdjm /*
2d3425be1Sdjm  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3da0d961cSdjm  *
4da0d961cSdjm  * libcbor is free software; you can redistribute it and/or modify
5da0d961cSdjm  * it under the terms of the MIT license. See LICENSE for details.
6da0d961cSdjm  */
7da0d961cSdjm 
8da0d961cSdjm #ifndef LIBCBOR_COMMON_H
9da0d961cSdjm #define LIBCBOR_COMMON_H
10da0d961cSdjm 
119e5c2ddcSdjm #include <assert.h>
129e5c2ddcSdjm #include <stdbool.h>
13da0d961cSdjm #include <stddef.h>
14da0d961cSdjm #include <stdint.h>
159e5c2ddcSdjm #include <stdlib.h>
164dcc46c4Sdjm #include "cbor/cbor_export.h"
17da0d961cSdjm #include "cbor/configuration.h"
189e5c2ddcSdjm #include "data.h"
19da0d961cSdjm 
20da0d961cSdjm #ifdef __cplusplus
21da0d961cSdjm extern "C" {
22da0d961cSdjm 
239e5c2ddcSdjm /**
244dcc46c4Sdjm  * C99 is not a subset of C++ -- 'restrict' qualifier is not a part of the
259e5c2ddcSdjm  * language. This is a workaround to keep it in C headers -- compilers allow
269e5c2ddcSdjm  * linking non-restrict signatures with restrict implementations.
27da0d961cSdjm  *
28da0d961cSdjm  * If you know a nicer way, please do let me know.
29da0d961cSdjm  */
30da0d961cSdjm #define CBOR_RESTRICT_POINTER
31da0d961cSdjm 
32da0d961cSdjm #else
33da0d961cSdjm 
34da0d961cSdjm // MSVC + C++ workaround
35da0d961cSdjm #define CBOR_RESTRICT_POINTER CBOR_RESTRICT_SPECIFIER
36da0d961cSdjm 
37da0d961cSdjm #endif
38da0d961cSdjm 
39da0d961cSdjm static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION;
40da0d961cSdjm static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION;
41da0d961cSdjm static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
42da0d961cSdjm 
439e5c2ddcSdjm #define CBOR_VERSION               \
444dcc46c4Sdjm   _CBOR_TO_STR(CBOR_MAJOR_VERSION) \
454dcc46c4Sdjm   "." _CBOR_TO_STR(CBOR_MINOR_VERSION) "." _CBOR_TO_STR(CBOR_PATCH_VERSION)
469e5c2ddcSdjm #define CBOR_HEX_VERSION \
479e5c2ddcSdjm   ((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)
48da0d961cSdjm 
499e5c2ddcSdjm /* http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing
509e5c2ddcSdjm  */
51da0d961cSdjm #ifdef DEBUG
52da0d961cSdjm #include <stdio.h>
534dcc46c4Sdjm #define _cbor_debug_print(fmt, ...)                                     \
549e5c2ddcSdjm   do {                                                                  \
55da0d961cSdjm     if (DEBUG)                                                          \
569e5c2ddcSdjm       fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \
579e5c2ddcSdjm               __VA_ARGS__);                                             \
58da0d961cSdjm   } while (0)
594dcc46c4Sdjm extern bool _cbor_enable_assert;
604dcc46c4Sdjm // Like `assert`, but can be dynamically disabled in tests to allow testing
614dcc46c4Sdjm // invalid behaviors.
624dcc46c4Sdjm #define CBOR_ASSERT(e) assert(!_cbor_enable_assert || (e))
634dcc46c4Sdjm #define _CBOR_TEST_DISABLE_ASSERT(block) \
644dcc46c4Sdjm   do {                                   \
654dcc46c4Sdjm     _cbor_enable_assert = false;         \
664dcc46c4Sdjm     block _cbor_enable_assert = true;    \
674dcc46c4Sdjm   } while (0)
68da0d961cSdjm #else
699e5c2ddcSdjm #define debug_print(fmt, ...) \
709e5c2ddcSdjm   do {                        \
719e5c2ddcSdjm   } while (0)
724dcc46c4Sdjm #define CBOR_ASSERT(e)
734dcc46c4Sdjm #define _CBOR_TEST_DISABLE_ASSERT(block) \
744dcc46c4Sdjm   do {                                   \
754dcc46c4Sdjm     block                                \
764dcc46c4Sdjm   } while (0)
77da0d961cSdjm #endif
78da0d961cSdjm 
794dcc46c4Sdjm #define _CBOR_TO_STR_(x) #x
804dcc46c4Sdjm #define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */
814dcc46c4Sdjm 
824dcc46c4Sdjm #ifdef __GNUC__
834dcc46c4Sdjm #define _CBOR_UNUSED(x) __attribute__((__unused__)) x
844dcc46c4Sdjm // TODO(https://github.com/PJK/libcbor/issues/247): Prefer [[nodiscard]] if
854dcc46c4Sdjm // available
86*196a8b7fSaoyama #if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ >= 4)
874dcc46c4Sdjm #define _CBOR_NODISCARD __attribute__((warn_unused_result))
88*196a8b7fSaoyama #else	/* gcc3 can not treat warn_unused_result attribute */
89*196a8b7fSaoyama #define _CBOR_NODISCARD
90*196a8b7fSaoyama #endif
914dcc46c4Sdjm #elif defined(_MSC_VER)
924dcc46c4Sdjm #define _CBOR_UNUSED(x) __pragma(warning(suppress : 4100 4101)) x
934dcc46c4Sdjm #define _CBOR_NODISCARD
944dcc46c4Sdjm #else
954dcc46c4Sdjm #define _CBOR_UNUSED(x) x
964dcc46c4Sdjm #define _CBOR_NODISCARD
974dcc46c4Sdjm #endif
984dcc46c4Sdjm 
994dcc46c4Sdjm #if 0 /* custom allocators are not supported on OpenBSD */
1004dcc46c4Sdjm typedef void *(*_cbor_malloc_t)(size_t);
1014dcc46c4Sdjm typedef void *(*_cbor_realloc_t)(void *, size_t);
1024dcc46c4Sdjm typedef void (*_cbor_free_t)(void *);
1034dcc46c4Sdjm 
1044dcc46c4Sdjm CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc;
1054dcc46c4Sdjm CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc;
1064dcc46c4Sdjm CBOR_EXPORT extern _cbor_free_t _cbor_free;
1074dcc46c4Sdjm #endif
108da0d961cSdjm 
1099e5c2ddcSdjm // Macro to short-circuit builder functions when memory allocation fails
1109e5c2ddcSdjm #define _CBOR_NOTNULL(cbor_item) \
1119e5c2ddcSdjm   do {                           \
1129e5c2ddcSdjm     if (cbor_item == NULL) {     \
1139e5c2ddcSdjm       return NULL;               \
1149e5c2ddcSdjm     }                            \
1159e5c2ddcSdjm   } while (0)
1169e5c2ddcSdjm 
1179e5c2ddcSdjm // Macro to short-circuit builders when memory allocation of nested data fails
1189e5c2ddcSdjm #define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \
1199e5c2ddcSdjm   do {                                              \
1209e5c2ddcSdjm     if (pointer == NULL) {                          \
1214dcc46c4Sdjm       _cbor_free(cbor_item);                        \
1229e5c2ddcSdjm       return NULL;                                  \
1239e5c2ddcSdjm     }                                               \
1249e5c2ddcSdjm   } while (0)
1259e5c2ddcSdjm 
126da0d961cSdjm /** Sets the memory management routines to use.
127da0d961cSdjm  *
128da0d961cSdjm  * \rst
1299e5c2ddcSdjm  * .. warning:: This function modifies the global state and should therefore be
1309e5c2ddcSdjm  *  used accordingly. Changing the memory handlers while allocated items exist
1319e5c2ddcSdjm  *  will result in a ``free``/``malloc`` mismatch. This function is not thread
1329e5c2ddcSdjm  *  safe with respect to both itself and all the other *libcbor* functions that
1339e5c2ddcSdjm  *  work with the heap.
1344dcc46c4Sdjm  *
135da0d961cSdjm  * .. note:: `realloc` implementation must correctly support `NULL` reallocation
1364dcc46c4Sdjm  *  (see e.g. http://en.cppreference.com/w/c/memory/realloc)
1374dcc46c4Sdjm  * \endrst
138da0d961cSdjm  *
139da0d961cSdjm  * @param custom_malloc malloc implementation
140da0d961cSdjm  * @param custom_realloc realloc implementation
141da0d961cSdjm  * @param custom_free free implementation
142da0d961cSdjm  */
1434dcc46c4Sdjm #if 0 /* not on OpenBSD */
1444dcc46c4Sdjm CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc,
1454dcc46c4Sdjm                                  _cbor_realloc_t custom_realloc,
1464dcc46c4Sdjm                                  _cbor_free_t custom_free);
147da0d961cSdjm #endif
148da0d961cSdjm 
149da0d961cSdjm /*
150da0d961cSdjm  * ============================================================================
151da0d961cSdjm  * Type manipulation
152da0d961cSdjm  * ============================================================================
153da0d961cSdjm  */
154da0d961cSdjm 
155da0d961cSdjm /** Get the type of the item
156da0d961cSdjm  *
157da0d961cSdjm  * @param item[borrow]
158da0d961cSdjm  * @return The type
159da0d961cSdjm  */
1604dcc46c4Sdjm _CBOR_NODISCARD
1614dcc46c4Sdjm CBOR_EXPORT cbor_type cbor_typeof(
1629e5c2ddcSdjm     const cbor_item_t *item); /* Will be inlined iff link-time opt is enabled */
163da0d961cSdjm 
164da0d961cSdjm /* Standard item types as described by the RFC */
165da0d961cSdjm 
166da0d961cSdjm /** Does the item have the appropriate major type?
167da0d961cSdjm  * @param item[borrow] the item
168da0d961cSdjm  * @return Is the item an #CBOR_TYPE_UINT?
169da0d961cSdjm  */
1704dcc46c4Sdjm _CBOR_NODISCARD
1714dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_uint(const cbor_item_t *item);
172da0d961cSdjm 
173da0d961cSdjm /** Does the item have the appropriate major type?
174da0d961cSdjm  * @param item[borrow] the item
175da0d961cSdjm  * @return Is the item a #CBOR_TYPE_NEGINT?
176da0d961cSdjm  */
1774dcc46c4Sdjm _CBOR_NODISCARD
1784dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_negint(const cbor_item_t *item);
179da0d961cSdjm 
180da0d961cSdjm /** Does the item have the appropriate major type?
181da0d961cSdjm  * @param item[borrow] the item
182da0d961cSdjm  * @return Is the item a #CBOR_TYPE_BYTESTRING?
183da0d961cSdjm  */
1844dcc46c4Sdjm _CBOR_NODISCARD
1854dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_bytestring(const cbor_item_t *item);
186da0d961cSdjm 
187da0d961cSdjm /** Does the item have the appropriate major type?
188da0d961cSdjm  * @param item[borrow] the item
189da0d961cSdjm  * @return Is the item a #CBOR_TYPE_STRING?
190da0d961cSdjm  */
1914dcc46c4Sdjm _CBOR_NODISCARD
1924dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_string(const cbor_item_t *item);
193da0d961cSdjm 
194da0d961cSdjm /** Does the item have the appropriate major type?
195da0d961cSdjm  * @param item[borrow] the item
196da0d961cSdjm  * @return Is the item an #CBOR_TYPE_ARRAY?
197da0d961cSdjm  */
1984dcc46c4Sdjm _CBOR_NODISCARD
1994dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_array(const cbor_item_t *item);
200da0d961cSdjm 
201da0d961cSdjm /** Does the item have the appropriate major type?
202da0d961cSdjm  * @param item[borrow] the item
203da0d961cSdjm  * @return Is the item a #CBOR_TYPE_MAP?
204da0d961cSdjm  */
2054dcc46c4Sdjm _CBOR_NODISCARD
2064dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_map(const cbor_item_t *item);
207da0d961cSdjm 
208da0d961cSdjm /** Does the item have the appropriate major type?
209da0d961cSdjm  * @param item[borrow] the item
210da0d961cSdjm  * @return Is the item a #CBOR_TYPE_TAG?
211da0d961cSdjm  */
2124dcc46c4Sdjm _CBOR_NODISCARD
2134dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_tag(const cbor_item_t *item);
214da0d961cSdjm 
215da0d961cSdjm /** Does the item have the appropriate major type?
216da0d961cSdjm  * @param item[borrow] the item
217da0d961cSdjm  * @return Is the item a #CBOR_TYPE_FLOAT_CTRL?
218da0d961cSdjm  */
2194dcc46c4Sdjm _CBOR_NODISCARD
2204dcc46c4Sdjm CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t *item);
221da0d961cSdjm 
222da0d961cSdjm /* Practical types with respect to their semantics (but not tag values) */
223da0d961cSdjm 
224da0d961cSdjm /** Is the item an integer, either positive or negative?
225da0d961cSdjm  * @param item[borrow] the item
226da0d961cSdjm  * @return  Is the item an integer, either positive or negative?
227da0d961cSdjm  */
2284dcc46c4Sdjm _CBOR_NODISCARD
2294dcc46c4Sdjm CBOR_EXPORT bool cbor_is_int(const cbor_item_t *item);
230da0d961cSdjm 
231da0d961cSdjm /** Is the item an a floating point number?
232da0d961cSdjm  * @param item[borrow] the item
233da0d961cSdjm  * @return  Is the item a floating point number?
234da0d961cSdjm  */
2354dcc46c4Sdjm _CBOR_NODISCARD
2364dcc46c4Sdjm CBOR_EXPORT bool cbor_is_float(const cbor_item_t *item);
237da0d961cSdjm 
238da0d961cSdjm /** Is the item an a boolean?
239da0d961cSdjm  * @param item[borrow] the item
240da0d961cSdjm  * @return  Is the item a boolean?
241da0d961cSdjm  */
2424dcc46c4Sdjm _CBOR_NODISCARD
2434dcc46c4Sdjm CBOR_EXPORT bool cbor_is_bool(const cbor_item_t *item);
244da0d961cSdjm 
245da0d961cSdjm /** Does this item represent `null`
2464dcc46c4Sdjm  *
247da0d961cSdjm  * \rst
2489e5c2ddcSdjm  * .. warning:: This is in no way related to the value of the pointer. Passing a
2494dcc46c4Sdjm  *  null pointer will most likely result in a crash.
2504dcc46c4Sdjm  * \endrst
2514dcc46c4Sdjm  *
252da0d961cSdjm  * @param item[borrow] the item
253da0d961cSdjm  * @return  Is the item (CBOR logical) null?
254da0d961cSdjm  */
2554dcc46c4Sdjm _CBOR_NODISCARD
2564dcc46c4Sdjm CBOR_EXPORT bool cbor_is_null(const cbor_item_t *item);
257da0d961cSdjm 
258da0d961cSdjm /** Does this item represent `undefined`
2594dcc46c4Sdjm  *
260da0d961cSdjm  * \rst
2619e5c2ddcSdjm  * .. warning:: Care must be taken to distinguish nulls and undefined values in
2624dcc46c4Sdjm  *  C.
2634dcc46c4Sdjm  * \endrst
2644dcc46c4Sdjm  *
265da0d961cSdjm  * @param item[borrow] the item
266da0d961cSdjm  * @return Is the item (CBOR logical) undefined?
267da0d961cSdjm  */
2684dcc46c4Sdjm _CBOR_NODISCARD
2694dcc46c4Sdjm CBOR_EXPORT bool cbor_is_undef(const cbor_item_t *item);
270da0d961cSdjm 
271da0d961cSdjm /*
272da0d961cSdjm  * ============================================================================
273da0d961cSdjm  * Memory management
274da0d961cSdjm  * ============================================================================
275da0d961cSdjm  */
276da0d961cSdjm 
277da0d961cSdjm /** Increases the reference count by one
278da0d961cSdjm  *
279da0d961cSdjm  * No dependent items are affected.
280da0d961cSdjm  *
281da0d961cSdjm  * @param item[incref] item the item
282da0d961cSdjm  * @return the input reference
283da0d961cSdjm  */
2844dcc46c4Sdjm CBOR_EXPORT cbor_item_t *cbor_incref(cbor_item_t *item);
285da0d961cSdjm 
286da0d961cSdjm /** Decreases the reference count by one, deallocating the item if needed
287da0d961cSdjm  *
288da0d961cSdjm  * In case the item is deallocated, the reference count of any dependent items
289da0d961cSdjm  * is adjusted accordingly in a recursive manner.
290da0d961cSdjm  *
291da0d961cSdjm  * @param item[take] the item. Set to `NULL` if deallocated
292da0d961cSdjm  */
2934dcc46c4Sdjm CBOR_EXPORT void cbor_decref(cbor_item_t **item);
294da0d961cSdjm 
295da0d961cSdjm /** Decreases the reference count by one, deallocating the item if needed
296da0d961cSdjm  *
2979e5c2ddcSdjm  * Convenience wrapper for #cbor_decref when its set-to-null behavior is not
2989e5c2ddcSdjm  * needed
299da0d961cSdjm  *
300da0d961cSdjm  * @param item[take] the item
301da0d961cSdjm  */
3024dcc46c4Sdjm CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t *item);
303da0d961cSdjm 
304da0d961cSdjm /** Get the reference count
305da0d961cSdjm  *
306da0d961cSdjm  * \rst
307da0d961cSdjm  * .. warning:: This does *not* account for transitive references.
308da0d961cSdjm  * \endrst
309da0d961cSdjm  *
310da0d961cSdjm  * @param item[borrow] the item
311da0d961cSdjm  * @return the reference count
312da0d961cSdjm  */
3134dcc46c4Sdjm _CBOR_NODISCARD
3144dcc46c4Sdjm CBOR_EXPORT size_t cbor_refcount(const cbor_item_t *item);
315da0d961cSdjm 
316da0d961cSdjm /** Provides CPP-like move construct
317da0d961cSdjm  *
3189e5c2ddcSdjm  * Decreases the reference count by one, but does not deallocate the item even
3199e5c2ddcSdjm  * if its refcount reaches zero. This is useful for passing intermediate values
3209e5c2ddcSdjm  * to functions that increase reference count. Should only be used with
3219e5c2ddcSdjm  * functions that `incref` their arguments.
322da0d961cSdjm  *
323da0d961cSdjm  * \rst
3249e5c2ddcSdjm  * .. warning:: If the item is moved without correctly increasing the reference
3254dcc46c4Sdjm  *  count afterwards, the memory will be leaked.
3264dcc46c4Sdjm  * \endrst
327da0d961cSdjm  *
328da0d961cSdjm  * @param item[take] the item
329da0d961cSdjm  * @return the item with reference count decreased by one
330da0d961cSdjm  */
3314dcc46c4Sdjm _CBOR_NODISCARD
3324dcc46c4Sdjm CBOR_EXPORT cbor_item_t *cbor_move(cbor_item_t *item);
333da0d961cSdjm 
334da0d961cSdjm #ifdef __cplusplus
335da0d961cSdjm }
336da0d961cSdjm #endif
337da0d961cSdjm 
338da0d961cSdjm #endif  // LIBCBOR_COMMON_H
339