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