xref: /openbsd/lib/libcbor/src/cbor/common.h (revision d415bd75)
1 /*
2  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3  *
4  * libcbor is free software; you can redistribute it and/or modify
5  * it under the terms of the MIT license. See LICENSE for details.
6  */
7 
8 #ifndef LIBCBOR_COMMON_H
9 #define LIBCBOR_COMMON_H
10 
11 #include <assert.h>
12 #include <stdbool.h>
13 #include <stddef.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include "cbor/cbor_export.h"
17 #include "cbor/configuration.h"
18 #include "data.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 
23 /**
24  * C99 is not a subset of C++ -- 'restrict' qualifier is not a part of the
25  * language. This is a workaround to keep it in C headers -- compilers allow
26  * 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_POINTER
31 
32 #else
33 
34 // MSVC + C++ workaround
35 #define CBOR_RESTRICT_POINTER CBOR_RESTRICT_SPECIFIER
36 
37 #endif
38 
39 static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION;
40 static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION;
41 static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
42 
43 #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)
48 
49 /* http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing
50  */
51 #ifdef DEBUG
52 #include <stdio.h>
53 #define _cbor_debug_print(fmt, ...)                                     \
54   do {                                                                  \
55     if (DEBUG)                                                          \
56       fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \
57               __VA_ARGS__);                                             \
58   } while (0)
59 extern bool _cbor_enable_assert;
60 // Like `assert`, but can be dynamically disabled in tests to allow testing
61 // invalid behaviors.
62 #define CBOR_ASSERT(e) assert(!_cbor_enable_assert || (e))
63 #define _CBOR_TEST_DISABLE_ASSERT(block) \
64   do {                                   \
65     _cbor_enable_assert = false;         \
66     block _cbor_enable_assert = true;    \
67   } while (0)
68 #else
69 #define debug_print(fmt, ...) \
70   do {                        \
71   } while (0)
72 #define CBOR_ASSERT(e)
73 #define _CBOR_TEST_DISABLE_ASSERT(block) \
74   do {                                   \
75     block                                \
76   } while (0)
77 #endif
78 
79 #define _CBOR_TO_STR_(x) #x
80 #define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */
81 
82 #ifdef __GNUC__
83 #define _CBOR_UNUSED(x) __attribute__((__unused__)) x
84 // TODO(https://github.com/PJK/libcbor/issues/247): Prefer [[nodiscard]] if
85 // available
86 #if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ >= 4)
87 #define _CBOR_NODISCARD __attribute__((warn_unused_result))
88 #else	/* gcc3 can not treat warn_unused_result attribute */
89 #define _CBOR_NODISCARD
90 #endif
91 #elif defined(_MSC_VER)
92 #define _CBOR_UNUSED(x) __pragma(warning(suppress : 4100 4101)) x
93 #define _CBOR_NODISCARD
94 #else
95 #define _CBOR_UNUSED(x) x
96 #define _CBOR_NODISCARD
97 #endif
98 
99 #if 0 /* custom allocators are not supported on OpenBSD */
100 typedef void *(*_cbor_malloc_t)(size_t);
101 typedef void *(*_cbor_realloc_t)(void *, size_t);
102 typedef void (*_cbor_free_t)(void *);
103 
104 CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc;
105 CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc;
106 CBOR_EXPORT extern _cbor_free_t _cbor_free;
107 #endif
108 
109 // Macro to short-circuit builder functions when memory allocation fails
110 #define _CBOR_NOTNULL(cbor_item) \
111   do {                           \
112     if (cbor_item == NULL) {     \
113       return NULL;               \
114     }                            \
115   } while (0)
116 
117 // Macro to short-circuit builders when memory allocation of nested data fails
118 #define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \
119   do {                                              \
120     if (pointer == NULL) {                          \
121       _cbor_free(cbor_item);                        \
122       return NULL;                                  \
123     }                                               \
124   } while (0)
125 
126 /** Sets the memory management routines to use.
127  *
128  * \rst
129  * .. warning:: This function modifies the global state and should therefore be
130  *  used accordingly. Changing the memory handlers while allocated items exist
131  *  will result in a ``free``/``malloc`` mismatch. This function is not thread
132  *  safe with respect to both itself and all the other *libcbor* functions that
133  *  work with the heap.
134  *
135  * .. note:: `realloc` implementation must correctly support `NULL` reallocation
136  *  (see e.g. http://en.cppreference.com/w/c/memory/realloc)
137  * \endrst
138  *
139  * @param custom_malloc malloc implementation
140  * @param custom_realloc realloc implementation
141  * @param custom_free free implementation
142  */
143 #if 0 /* not on OpenBSD */
144 CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc,
145                                  _cbor_realloc_t custom_realloc,
146                                  _cbor_free_t custom_free);
147 #endif
148 
149 /*
150  * ============================================================================
151  * Type manipulation
152  * ============================================================================
153  */
154 
155 /** Get the type of the item
156  *
157  * @param item[borrow]
158  * @return The type
159  */
160 _CBOR_NODISCARD
161 CBOR_EXPORT cbor_type cbor_typeof(
162     const cbor_item_t *item); /* Will be inlined iff link-time opt is enabled */
163 
164 /* Standard item types as described by the RFC */
165 
166 /** Does the item have the appropriate major type?
167  * @param item[borrow] the item
168  * @return Is the item an #CBOR_TYPE_UINT?
169  */
170 _CBOR_NODISCARD
171 CBOR_EXPORT bool cbor_isa_uint(const cbor_item_t *item);
172 
173 /** Does the item have the appropriate major type?
174  * @param item[borrow] the item
175  * @return Is the item a #CBOR_TYPE_NEGINT?
176  */
177 _CBOR_NODISCARD
178 CBOR_EXPORT bool cbor_isa_negint(const cbor_item_t *item);
179 
180 /** Does the item have the appropriate major type?
181  * @param item[borrow] the item
182  * @return Is the item a #CBOR_TYPE_BYTESTRING?
183  */
184 _CBOR_NODISCARD
185 CBOR_EXPORT bool cbor_isa_bytestring(const cbor_item_t *item);
186 
187 /** Does the item have the appropriate major type?
188  * @param item[borrow] the item
189  * @return Is the item a #CBOR_TYPE_STRING?
190  */
191 _CBOR_NODISCARD
192 CBOR_EXPORT bool cbor_isa_string(const cbor_item_t *item);
193 
194 /** Does the item have the appropriate major type?
195  * @param item[borrow] the item
196  * @return Is the item an #CBOR_TYPE_ARRAY?
197  */
198 _CBOR_NODISCARD
199 CBOR_EXPORT bool cbor_isa_array(const cbor_item_t *item);
200 
201 /** Does the item have the appropriate major type?
202  * @param item[borrow] the item
203  * @return Is the item a #CBOR_TYPE_MAP?
204  */
205 _CBOR_NODISCARD
206 CBOR_EXPORT bool cbor_isa_map(const cbor_item_t *item);
207 
208 /** Does the item have the appropriate major type?
209  * @param item[borrow] the item
210  * @return Is the item a #CBOR_TYPE_TAG?
211  */
212 _CBOR_NODISCARD
213 CBOR_EXPORT bool cbor_isa_tag(const cbor_item_t *item);
214 
215 /** Does the item have the appropriate major type?
216  * @param item[borrow] the item
217  * @return Is the item a #CBOR_TYPE_FLOAT_CTRL?
218  */
219 _CBOR_NODISCARD
220 CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t *item);
221 
222 /* Practical types with respect to their semantics (but not tag values) */
223 
224 /** Is the item an integer, either positive or negative?
225  * @param item[borrow] the item
226  * @return  Is the item an integer, either positive or negative?
227  */
228 _CBOR_NODISCARD
229 CBOR_EXPORT bool cbor_is_int(const cbor_item_t *item);
230 
231 /** Is the item an a floating point number?
232  * @param item[borrow] the item
233  * @return  Is the item a floating point number?
234  */
235 _CBOR_NODISCARD
236 CBOR_EXPORT bool cbor_is_float(const cbor_item_t *item);
237 
238 /** Is the item an a boolean?
239  * @param item[borrow] the item
240  * @return  Is the item a boolean?
241  */
242 _CBOR_NODISCARD
243 CBOR_EXPORT bool cbor_is_bool(const cbor_item_t *item);
244 
245 /** Does this item represent `null`
246  *
247  * \rst
248  * .. warning:: This is in no way related to the value of the pointer. Passing a
249  *  null pointer will most likely result in a crash.
250  * \endrst
251  *
252  * @param item[borrow] the item
253  * @return  Is the item (CBOR logical) null?
254  */
255 _CBOR_NODISCARD
256 CBOR_EXPORT bool cbor_is_null(const cbor_item_t *item);
257 
258 /** Does this item represent `undefined`
259  *
260  * \rst
261  * .. warning:: Care must be taken to distinguish nulls and undefined values in
262  *  C.
263  * \endrst
264  *
265  * @param item[borrow] the item
266  * @return Is the item (CBOR logical) undefined?
267  */
268 _CBOR_NODISCARD
269 CBOR_EXPORT bool cbor_is_undef(const cbor_item_t *item);
270 
271 /*
272  * ============================================================================
273  * Memory management
274  * ============================================================================
275  */
276 
277 /** Increases the reference count by one
278  *
279  * No dependent items are affected.
280  *
281  * @param item[incref] item the item
282  * @return the input reference
283  */
284 CBOR_EXPORT cbor_item_t *cbor_incref(cbor_item_t *item);
285 
286 /** Decreases the reference count by one, deallocating the item if needed
287  *
288  * In case the item is deallocated, the reference count of any dependent items
289  * is adjusted accordingly in a recursive manner.
290  *
291  * @param item[take] the item. Set to `NULL` if deallocated
292  */
293 CBOR_EXPORT void cbor_decref(cbor_item_t **item);
294 
295 /** Decreases the reference count by one, deallocating the item if needed
296  *
297  * Convenience wrapper for #cbor_decref when its set-to-null behavior is not
298  * needed
299  *
300  * @param item[take] the item
301  */
302 CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t *item);
303 
304 /** Get the reference count
305  *
306  * \rst
307  * .. warning:: This does *not* account for transitive references.
308  * \endrst
309  *
310  * @param item[borrow] the item
311  * @return the reference count
312  */
313 _CBOR_NODISCARD
314 CBOR_EXPORT size_t cbor_refcount(const cbor_item_t *item);
315 
316 /** Provides CPP-like move construct
317  *
318  * Decreases the reference count by one, but does not deallocate the item even
319  * if its refcount reaches zero. This is useful for passing intermediate values
320  * to functions that increase reference count. Should only be used with
321  * functions that `incref` their arguments.
322  *
323  * \rst
324  * .. warning:: If the item is moved without correctly increasing the reference
325  *  count afterwards, the memory will be leaked.
326  * \endrst
327  *
328  * @param item[take] the item
329  * @return the item with reference count decreased by one
330  */
331 _CBOR_NODISCARD
332 CBOR_EXPORT cbor_item_t *cbor_move(cbor_item_t *item);
333 
334 #ifdef __cplusplus
335 }
336 #endif
337 
338 #endif  // LIBCBOR_COMMON_H
339