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