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_ASSERT_VALID_TYPE(item_type) \ 81 CBOR_ASSERT(item_type >= CBOR_TYPE_UINT && item_type <= CBOR_TYPE_FLOAT_CTRL); 82 83 #define _CBOR_TO_STR_(x) #x 84 #define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */ 85 86 #ifdef CBOR_HAS_NODISCARD_ATTRIBUTE 87 #define CBOR_NODISCARD [[nodiscard]] 88 #else 89 #define CBOR_NODISCARD 90 #endif 91 92 #ifdef __GNUC__ 93 #define _CBOR_UNUSED __attribute__((__unused__)) 94 // Fall back to __attribute__((warn_unused_result)) if we don't have 95 // [[nodiscard]] 96 #ifndef CBOR_HAS_NODISCARD_ATTRIBUTE 97 #define _CBOR_NODISCARD __attribute__((warn_unused_result)) 98 #endif 99 #elif defined(_MSC_VER) 100 #define _CBOR_UNUSED __pragma(warning(suppress : 4100 4101)) 101 #define _CBOR_NODISCARD 102 #else 103 #define _CBOR_UNUSED 104 #define _CBOR_NODISCARD 105 #endif 106 107 #ifdef CBOR_HAS_BUILTIN_UNREACHABLE 108 #define _CBOR_UNREACHABLE __builtin_unreachable() 109 #else 110 #define _CBOR_UNREACHABLE 111 #endif 112 113 typedef void* (*_cbor_malloc_t)(size_t); 114 typedef void* (*_cbor_realloc_t)(void*, size_t); 115 typedef void (*_cbor_free_t)(void*); 116 117 CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc; 118 CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc; 119 CBOR_EXPORT extern _cbor_free_t _cbor_free; 120 121 // Macro to short-circuit builder functions when memory allocation fails 122 #define _CBOR_NOTNULL(cbor_item) \ 123 do { \ 124 if (cbor_item == NULL) { \ 125 return NULL; \ 126 } \ 127 } while (0) 128 129 // Macro to short-circuit builders when memory allocation of nested data 130 // fails 131 #define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \ 132 do { \ 133 if (pointer == NULL) { \ 134 _cbor_free(cbor_item); \ 135 return NULL; \ 136 } \ 137 } while (0) 138 139 /** Sets the memory management routines to use. 140 * 141 * By default, libcbor will use the standard library `malloc`, `realloc`, 142 * and `free`. 143 * 144 * \rst 145 * .. warning:: 146 * This function modifies the global state and should 147 * therefore be used accordingly. Changing the memory handlers while 148 * allocated items exist will result in a ``free``/``malloc`` mismatch. 149 * This function is not thread safe with respect to both itself and all 150 * the other *libcbor* functions that work with the heap. 151 * 152 * .. note:: 153 * `realloc` implementation must correctly support `NULL` 154 * reallocation (see e.g. http://en.cppreference.com/w/c/memory/realloc) 155 * 156 * \endrst 157 * 158 * @param custom_malloc malloc implementation 159 * @param custom_realloc realloc implementation 160 * @param custom_free free implementation 161 */ 162 CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc, 163 _cbor_realloc_t custom_realloc, 164 _cbor_free_t custom_free); 165 166 /* 167 * ============================================================================ 168 * Type manipulation 169 * ============================================================================ 170 */ 171 172 /** Get the type of the item 173 * 174 * @param item 175 * @return The type 176 */ 177 _CBOR_NODISCARD 178 CBOR_EXPORT cbor_type cbor_typeof( 179 const cbor_item_t* item); /* Will be inlined iff link-time opt is enabled */ 180 181 /* Standard CBOR Major item types */ 182 183 /** Does the item have the appropriate major type? 184 * @param item the item 185 * @return Is the item an #CBOR_TYPE_UINT? 186 */ 187 _CBOR_NODISCARD 188 CBOR_EXPORT bool cbor_isa_uint(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 a #CBOR_TYPE_NEGINT? 193 */ 194 _CBOR_NODISCARD 195 CBOR_EXPORT bool cbor_isa_negint(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_BYTESTRING? 200 */ 201 _CBOR_NODISCARD 202 CBOR_EXPORT bool cbor_isa_bytestring(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_STRING? 207 */ 208 _CBOR_NODISCARD 209 CBOR_EXPORT bool cbor_isa_string(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 an #CBOR_TYPE_ARRAY? 214 */ 215 _CBOR_NODISCARD 216 CBOR_EXPORT bool cbor_isa_array(const cbor_item_t* item); 217 218 /** Does the item have the appropriate major type? 219 * @param item the item 220 * @return Is the item a #CBOR_TYPE_MAP? 221 */ 222 _CBOR_NODISCARD 223 CBOR_EXPORT bool cbor_isa_map(const cbor_item_t* item); 224 225 /** Does the item have the appropriate major type? 226 * @param item the item 227 * @return Is the item a #CBOR_TYPE_TAG? 228 */ 229 _CBOR_NODISCARD 230 CBOR_EXPORT bool cbor_isa_tag(const cbor_item_t* item); 231 232 /** Does the item have the appropriate major type? 233 * @param item the item 234 * @return Is the item a #CBOR_TYPE_FLOAT_CTRL? 235 */ 236 _CBOR_NODISCARD 237 CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t* item); 238 239 /* Practical types with respect to their semantics (but not tag values) */ 240 241 /** Is the item an integer, either positive or negative? 242 * @param item the item 243 * @return Is the item an integer, either positive or negative? 244 */ 245 _CBOR_NODISCARD 246 CBOR_EXPORT bool cbor_is_int(const cbor_item_t* item); 247 248 /** Is the item an a floating point number? 249 * @param item the item 250 * @return Is the item a floating point number? 251 */ 252 _CBOR_NODISCARD 253 CBOR_EXPORT bool cbor_is_float(const cbor_item_t* item); 254 255 /** Is the item an a boolean? 256 * @param item the item 257 * @return Is the item a boolean? 258 */ 259 _CBOR_NODISCARD 260 CBOR_EXPORT bool cbor_is_bool(const cbor_item_t* item); 261 262 /** Does this item represent `null` 263 * 264 * \rst 265 * .. warning:: 266 * This is in no way related to the value of the pointer. 267 * Passing a null pointer will most likely result in a crash. 268 * \endrst 269 * 270 * @param item the item 271 * @return Is the item (CBOR logical) null? 272 */ 273 _CBOR_NODISCARD 274 CBOR_EXPORT bool cbor_is_null(const cbor_item_t* item); 275 276 /** Does this item represent `undefined` 277 * 278 * \rst 279 * .. warning:: 280 * Care must be taken to distinguish nulls and undefined values in C. 281 * \endrst 282 * 283 * @param item the item 284 * @return Is the item (CBOR logical) undefined? 285 */ 286 _CBOR_NODISCARD 287 CBOR_EXPORT bool cbor_is_undef(const cbor_item_t* item); 288 289 /* 290 * ============================================================================ 291 * Memory management 292 * ============================================================================ 293 */ 294 295 /** Increases the item's reference count by one 296 * 297 * Constant complexity; items referring to this one or items being 298 * referred to are not updated. 299 * 300 * This function can be used to extend reference counting to client code. 301 * 302 * @param item Reference to an item 303 * @return The input \p item 304 */ 305 CBOR_EXPORT cbor_item_t* cbor_incref(cbor_item_t* item); 306 307 /** Decreases the item's reference count by one, deallocating the item if 308 * needed 309 * 310 * In case the item is deallocated, the reference count of all items this 311 * item references will also be #cbor_decref 'ed recursively. 312 * 313 * @param item Reference to an item. Will be set to `NULL` if deallocated 314 */ 315 CBOR_EXPORT void cbor_decref(cbor_item_t** item); 316 317 /** Decreases the item's reference count by one, deallocating the item if 318 * needed 319 * 320 * Convenience wrapper for #cbor_decref when its set-to-null behavior is 321 * not needed 322 * 323 * @param item Reference to an item 324 */ 325 CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t* item); 326 327 /** Get the item's reference count 328 * 329 * \rst 330 * .. warning:: 331 * This does *not* account for transitive references. 332 * \endrst 333 * 334 * @todo Add some inline examples for reference counting 335 * 336 * @param item the item 337 * @return the reference count 338 */ 339 _CBOR_NODISCARD 340 CBOR_EXPORT size_t cbor_refcount(const cbor_item_t* item); 341 342 /** Provides CPP-like move construct 343 * 344 * Decreases the reference count by one, but does not deallocate the item 345 * even if its refcount reaches zero. This is useful for passing 346 * intermediate values to functions that increase reference count. Should 347 * only be used with functions that `incref` their arguments. 348 * 349 * \rst 350 * .. warning:: 351 * If the item is moved without correctly increasing the 352 * reference count afterwards, the memory will be leaked. 353 * \endrst 354 * 355 * @param item Reference to an item 356 * @return the item with reference count decreased by one 357 */ 358 _CBOR_NODISCARD 359 CBOR_EXPORT cbor_item_t* cbor_move(cbor_item_t* item); 360 361 #ifdef __cplusplus 362 } 363 #endif 364 365 #endif // LIBCBOR_COMMON_H 366