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