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