1 /** 2 * \file 3 * \brief 4 * CBOR parsing 5 */ 6 7 #ifndef CN_CBOR_H 8 #define CN_CBOR_H 9 10 #ifdef __cplusplus 11 extern "C" { 12 #endif 13 #ifdef EMACS_INDENTATION_HELPER 14 } /* Duh. */ 15 #endif 16 17 #include <stdbool.h> 18 #include <stdint.h> 19 #include <unistd.h> 20 21 /** 22 * All of the different kinds of CBOR values. 23 */ 24 typedef enum cn_cbor_type { 25 /** false */ 26 CN_CBOR_FALSE, 27 /** true */ 28 CN_CBOR_TRUE, 29 /** null */ 30 CN_CBOR_NULL, 31 /** undefined */ 32 CN_CBOR_UNDEF, 33 /** Positive integers */ 34 CN_CBOR_UINT, 35 /** Negative integers */ 36 CN_CBOR_INT, 37 /** Byte string */ 38 CN_CBOR_BYTES, 39 /** UTF-8 string */ 40 CN_CBOR_TEXT, 41 /** Byte string, in chunks. Each chunk is a child. */ 42 CN_CBOR_BYTES_CHUNKED, 43 /** UTF-8 string, in chunks. Each chunk is a child */ 44 CN_CBOR_TEXT_CHUNKED, 45 /** Array of CBOR values. Each array element is a child, in order */ 46 CN_CBOR_ARRAY, 47 /** Map of key/value pairs. Each key and value is a child, alternating. */ 48 CN_CBOR_MAP, 49 /** Tag describing the next value. The next value is the single child. */ 50 CN_CBOR_TAG, 51 /** Simple value, other than the defined ones */ 52 CN_CBOR_SIMPLE, 53 /** Doubles, floats, and half-floats */ 54 CN_CBOR_DOUBLE, 55 /** An error has occurred */ 56 CN_CBOR_INVALID 57 } cn_cbor_type; 58 59 /** 60 * Flags used during parsing. Not useful for consumers of the 61 * `cn_cbor` structure. 62 */ 63 typedef enum cn_cbor_flags { 64 /** The count field will be used for parsing */ 65 CN_CBOR_FL_COUNT = 1, 66 /** An indefinite number of children */ 67 CN_CBOR_FL_INDEF = 2, 68 /** Not used yet; the structure must free the v.str pointer when the 69 structure is freed */ 70 CN_CBOR_FL_OWNER = 0x80, /* of str */ 71 } cn_cbor_flags; 72 73 /** 74 * A CBOR value 75 */ 76 typedef struct cn_cbor { 77 /** The type of value */ 78 cn_cbor_type type; 79 /** Flags used at parse time */ 80 cn_cbor_flags flags; 81 /** Data associated with the value; different branches of the union are 82 used depending on the `type` field. */ 83 union { 84 /** CN_CBOR_BYTES */ 85 const uint8_t* bytes; 86 /** CN_CBOR_TEXT */ 87 const char* str; 88 /** CN_CBOR_INT */ 89 long sint; 90 /** CN_CBOR_UINT */ 91 unsigned long uint; 92 /** CN_CBOR_DOUBLE */ 93 double dbl; 94 /** for use during parsing */ 95 unsigned long count; 96 } v; /* TBD: optimize immediate */ 97 /** Number of children. 98 * @note: for maps, this is 2x the number of entries */ 99 int length; 100 /** The first child value */ 101 struct cn_cbor* first_child; 102 /** The last child value */ 103 struct cn_cbor* last_child; 104 /** The sibling after this one, or NULL if this is the last */ 105 struct cn_cbor* next; 106 /** The parent of this value, or NULL if this is the root */ 107 struct cn_cbor* parent; 108 } cn_cbor; 109 110 /** 111 * All of the different kinds of errors 112 */ 113 typedef enum cn_cbor_error { 114 /** No error has occurred */ 115 CN_CBOR_NO_ERROR, 116 /** More data was expected while parsing */ 117 CN_CBOR_ERR_OUT_OF_DATA, 118 /** Some extra data was left over at the end of parsing */ 119 CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED, 120 /** A map should be alternating keys and values. A break was found 121 when a value was expected */ 122 CN_CBOR_ERR_ODD_SIZE_INDEF_MAP, 123 /** A break was found where it wasn't expected */ 124 CN_CBOR_ERR_BREAK_OUTSIDE_INDEF, 125 /** Indefinite encoding works for bstrs, strings, arrays, and maps. 126 A different major type tried to use it. */ 127 CN_CBOR_ERR_MT_UNDEF_FOR_INDEF, 128 /** Additional Information values 28-30 are reserved */ 129 CN_CBOR_ERR_RESERVED_AI, 130 /** A chunked encoding was used for a string or bstr, and one of the elements 131 wasn't the expected (string/bstr) type */ 132 CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING, 133 /** An invalid parameter was passed to a function */ 134 CN_CBOR_ERR_INVALID_PARAMETER, 135 /** Allocation failed */ 136 CN_CBOR_ERR_OUT_OF_MEMORY, 137 /** A float was encountered during parse but the library was built without 138 support for float types. */ 139 CN_CBOR_ERR_FLOAT_NOT_SUPPORTED 140 } cn_cbor_error; 141 142 /** 143 * Strings matching the `cn_cbor_error` conditions. 144 * 145 * @todo: turn into a function to make the type safety more clear? 146 */ 147 extern const char *cn_cbor_error_str[]; 148 149 /** 150 * Errors 151 */ 152 typedef struct cn_cbor_errback { 153 /** The position in the input where the erorr happened */ 154 int pos; 155 /** The error, or CN_CBOR_NO_ERROR if none */ 156 cn_cbor_error err; 157 } cn_cbor_errback; 158 159 #ifdef USE_CBOR_CONTEXT 160 161 /** 162 * Allocate and zero out memory. `count` elements of `size` are required, 163 * as for `calloc(3)`. The `context` is the `cn_cbor_context` passed in 164 * earlier to the CBOR routine. 165 * 166 * @param[in] count The number of items to allocate 167 * @param[in] size The size of each item 168 * @param[in] context The allocation context 169 */ 170 typedef void* (*cn_calloc_func)(size_t count, size_t size, void *context); 171 172 /** 173 * Free memory previously allocated with a context. If using a pool allocator, 174 * this function will often be a no-op, but it must be supplied in order to 175 * prevent the CBOR library from calling `free(3)`. 176 * 177 * @note: it may be that this is never needed; if so, it will be removed for 178 * clarity and speed. 179 * 180 * @param context [description] 181 * @return [description] 182 */ 183 typedef void (*cn_free_func)(void *ptr, void *context); 184 185 /** 186 * The allocation context. 187 */ 188 typedef struct cn_cbor_context { 189 /** The pool `calloc` routine. Must allocate and zero. */ 190 cn_calloc_func calloc_func; 191 /** The pool `free` routine. Often a no-op, but required. */ 192 cn_free_func free_func; 193 /** Typically, the pool object, to be used when calling `calloc_func` 194 * and `free_func` */ 195 void *context; 196 } cn_cbor_context; 197 198 /** When USE_CBOR_CONTEXT is defined, many functions take an extra `context` 199 * parameter */ 200 #define CBOR_CONTEXT , cn_cbor_context *context 201 /** When USE_CBOR_CONTEXT is defined, some functions take an extra `context` 202 * parameter at the beginning */ 203 #define CBOR_CONTEXT_COMMA cn_cbor_context *context, 204 205 #else 206 207 #define CBOR_CONTEXT 208 #define CBOR_CONTEXT_COMMA 209 210 #endif 211 212 /** 213 * Decode an array of CBOR bytes into structures. 214 * 215 * @param[in] buf The array of bytes to parse 216 * @param[in] len The number of bytes in the array 217 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 218 * @param[out] errp Error, if NULL is returned 219 * @return The parsed CBOR structure, or NULL on error 220 */ 221 cn_cbor* cn_cbor_decode(const uint8_t *buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp); 222 223 /** 224 * Get a value from a CBOR map that has the given string as a key. 225 * 226 * @param[in] cb The CBOR map 227 * @param[in] key The string to look up in the map 228 * @return The matching value, or NULL if the key is not found 229 */ 230 cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key); 231 232 /** 233 * Get a value from a CBOR map that has the given integer as a key. 234 * 235 * @param[in] cb The CBOR map 236 * @param[in] key The int to look up in the map 237 * @return The matching value, or NULL if the key is not found 238 */ 239 cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key); 240 241 /** 242 * Get the item with the given index from a CBOR array. 243 * 244 * @param[in] cb The CBOR map 245 * @param[in] idx The array index 246 * @return The matching value, or NULL if the index is invalid 247 */ 248 cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx); 249 250 /** 251 * Free the given CBOR structure. 252 * You MUST NOT try to free a cn_cbor structure with a parent (i.e., one 253 * that is not a root in the tree). 254 * 255 * @param[in] cb The CBOR value to free. May be NULL, or a root object. 256 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 257 */ 258 void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT); 259 260 /** 261 * Write a CBOR value and all of the child values. 262 * 263 * @param[in] buf The buffer into which to write 264 * @param[in] buf_offset The offset (in bytes) from the beginning of the buffer 265 * to start writing at 266 * @param[in] buf_size The total length (in bytes) of the buffer 267 * @param[in] cb [description] 268 * @return -1 on fail, or number of bytes written 269 */ 270 ssize_t cn_cbor_encoder_write(uint8_t *buf, 271 size_t buf_offset, 272 size_t buf_size, 273 const cn_cbor *cb); 274 275 /** 276 * Create a CBOR map. 277 * 278 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 279 * @param[out] errp Error, if NULL is returned 280 * @return The created map, or NULL on error 281 */ 282 cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); 283 284 /** 285 * Create a CBOR byte string. The data in the byte string is *not* owned 286 * by the CBOR object, so it is not freed automatically. 287 * 288 * @param[in] data The data 289 * @param[in] len The number of bytes of data 290 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 291 * @param[out] errp Error, if NULL is returned 292 * @return The created object, or NULL on error 293 */ 294 cn_cbor* cn_cbor_data_create(const uint8_t* data, int len 295 CBOR_CONTEXT, 296 cn_cbor_errback *errp); 297 298 /** 299 * Create a CBOR UTF-8 string. The data is not checked for UTF-8 correctness. 300 * The data being stored in the string is *not* owned the CBOR object, so it is 301 * not freed automatically. 302 * 303 * @note: Do NOT use this function with untrusted data. It calls strlen, and 304 * relies on proper NULL-termination. 305 * 306 * @param[in] data NULL-terminated UTF-8 string 307 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 308 * @param[out] errp Error, if NULL is returned 309 * @return The created object, or NULL on error 310 */ 311 cn_cbor* cn_cbor_string_create(const char* data 312 CBOR_CONTEXT, 313 cn_cbor_errback *errp); 314 315 /** 316 * Create a CBOR integer (either positive or negative). 317 * 318 * @param[in] value the value of the integer 319 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 320 * @param[out] errp Error, if NULL is returned 321 * @return The created object, or NULL on error 322 */ 323 cn_cbor* cn_cbor_int_create(int64_t value 324 CBOR_CONTEXT, 325 cn_cbor_errback *errp); 326 327 /** 328 * Put a CBOR object into a map with a CBOR object key. Duplicate checks are NOT 329 * currently performed. 330 * 331 * @param[in] cb_map The map to insert into 332 * @param[in] key The key 333 * @param[in] cb_value The value 334 * @param[out] errp Error 335 * @return True on success 336 */ 337 bool cn_cbor_map_put(cn_cbor* cb_map, 338 cn_cbor *cb_key, cn_cbor *cb_value, 339 cn_cbor_errback *errp); 340 341 /** 342 * Put a CBOR object into a map with an integer key. Duplicate checks are NOT 343 * currently performed. 344 * 345 * @param[in] cb_map The map to insert into 346 * @param[in] key The integer key 347 * @param[in] cb_value The value 348 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 349 * @param[out] errp Error 350 * @return True on success 351 */ 352 bool cn_cbor_mapput_int(cn_cbor* cb_map, 353 int64_t key, cn_cbor* cb_value 354 CBOR_CONTEXT, 355 cn_cbor_errback *errp); 356 357 /** 358 * Put a CBOR object into a map with a string key. Duplicate checks are NOT 359 * currently performed. 360 * 361 * @note: do not call this routine with untrusted string data. It calls 362 * strlen, and requires a properly NULL-terminated key. 363 * 364 * @param[in] cb_map The map to insert into 365 * @param[in] key The string key 366 * @param[in] cb_value The value 367 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 368 * @param[out] errp Error 369 * @return True on success 370 */ 371 bool cn_cbor_mapput_string(cn_cbor* cb_map, 372 const char* key, cn_cbor* cb_value 373 CBOR_CONTEXT, 374 cn_cbor_errback *errp); 375 376 /** 377 * Create a CBOR array 378 * 379 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 380 * @param[out] errp Error, if NULL is returned 381 * @return The created object, or NULL on error 382 */ 383 cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); 384 385 /** 386 * Append an item to the end of a CBOR array. 387 * 388 * @param[in] cb_array The array into which to insert 389 * @param[in] cb_value The value to insert 390 * @param[out] errp Error 391 * @return True on success 392 */ 393 bool cn_cbor_array_append(cn_cbor* cb_array, 394 cn_cbor* cb_value, 395 cn_cbor_errback *errp); 396 397 #ifdef __cplusplus 398 } 399 #endif 400 401 #endif /* CN_CBOR_H */ 402