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 item types as described by the RFC */ 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