| |
| /** |
| * \file |
| * \brief |
| * CBOR parsing |
| */ |
| |
| #ifndef CN_CBOR_H |
| #define CN_CBOR_H |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| #ifdef EMACS_INDENTATION_HELPER |
| } /* Duh. */ |
| #endif |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| |
| /** |
| * All of the different kinds of CBOR values. |
| */ |
| typedef enum cn_cbor_type { |
| /** false */ |
| CN_CBOR_FALSE, |
| /** true */ |
| CN_CBOR_TRUE, |
| /** null */ |
| CN_CBOR_NULL, |
| /** undefined */ |
| CN_CBOR_UNDEF, |
| /** Positive integers */ |
| CN_CBOR_UINT, |
| /** Negative integers */ |
| CN_CBOR_INT, |
| /** Byte string */ |
| CN_CBOR_BYTES, |
| /** UTF-8 string */ |
| CN_CBOR_TEXT, |
| /** Byte string, in chunks. Each chunk is a child. */ |
| CN_CBOR_BYTES_CHUNKED, |
| /** UTF-8 string, in chunks. Each chunk is a child */ |
| CN_CBOR_TEXT_CHUNKED, |
| /** Array of CBOR values. Each array element is a child, in order */ |
| CN_CBOR_ARRAY, |
| /** Map of key/value pairs. Each key and value is a child, alternating. */ |
| CN_CBOR_MAP, |
| /** Tag describing the next value. The next value is the single child. */ |
| CN_CBOR_TAG, |
| /** Simple value, other than the defined ones */ |
| CN_CBOR_SIMPLE, |
| /** Doubles, floats, and half-floats */ |
| CN_CBOR_DOUBLE, |
| /** Floats, and half-floats */ |
| CN_CBOR_FLOAT, |
| /** An error has occurred */ |
| CN_CBOR_INVALID |
| } cn_cbor_type; |
| |
| /** |
| * Flags used during parsing. Not useful for consumers of the |
| * `cn_cbor` structure. |
| */ |
| typedef enum cn_cbor_flags { |
| /** The count field will be used for parsing */ |
| CN_CBOR_FL_COUNT = 1, |
| /** An indefinite number of children */ |
| CN_CBOR_FL_INDEF = 2, |
| /** Not used yet; the structure must free the v.str pointer when the |
| structure is freed */ |
| CN_CBOR_FL_OWNER = 0x80, /* of str */ |
| } cn_cbor_flags; |
| |
| /** |
| * A CBOR value |
| */ |
| typedef struct cn_cbor { |
| /** The type of value */ |
| cn_cbor_type type; |
| /** Flags used at parse time */ |
| cn_cbor_flags flags; |
| /** Data associated with the value; different branches of the union are |
| used depending on the `type` field. */ |
| union { |
| /** CN_CBOR_BYTES */ |
| const uint8_t* bytes; |
| /** CN_CBOR_TEXT */ |
| const char* str; |
| /** CN_CBOR_INT */ |
| long sint; |
| /** CN_CBOR_UINT */ |
| unsigned long uint; |
| /** CN_CBOR_DOUBLE */ |
| double dbl; |
| /** CN_CBOR_FLOAT */ |
| float f; |
| /** for use during parsing */ |
| unsigned long count; |
| } v; /* TBD: optimize immediate */ |
| /** Number of children. |
| * @note: for maps, this is 2x the number of entries */ |
| int length; |
| /** The first child value */ |
| struct cn_cbor* first_child; |
| /** The last child value */ |
| struct cn_cbor* last_child; |
| /** The sibling after this one, or NULL if this is the last */ |
| struct cn_cbor* next; |
| /** The parent of this value, or NULL if this is the root */ |
| struct cn_cbor* parent; |
| } cn_cbor; |
| |
| /** |
| * All of the different kinds of errors |
| */ |
| typedef enum cn_cbor_error { |
| /** No error has occurred */ |
| CN_CBOR_NO_ERROR, |
| /** More data was expected while parsing */ |
| CN_CBOR_ERR_OUT_OF_DATA, |
| /** Some extra data was left over at the end of parsing */ |
| CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED, |
| /** A map should be alternating keys and values. A break was found |
| when a value was expected */ |
| CN_CBOR_ERR_ODD_SIZE_INDEF_MAP, |
| /** A break was found where it wasn't expected */ |
| CN_CBOR_ERR_BREAK_OUTSIDE_INDEF, |
| /** Indefinite encoding works for bstrs, strings, arrays, and maps. |
| A different major type tried to use it. */ |
| CN_CBOR_ERR_MT_UNDEF_FOR_INDEF, |
| /** Additional Information values 28-30 are reserved */ |
| CN_CBOR_ERR_RESERVED_AI, |
| /** A chunked encoding was used for a string or bstr, and one of the elements |
| wasn't the expected (string/bstr) type */ |
| CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING, |
| /** An invalid parameter was passed to a function */ |
| CN_CBOR_ERR_INVALID_PARAMETER, |
| /** Allocation failed */ |
| CN_CBOR_ERR_OUT_OF_MEMORY, |
| /** A float was encountered during parse but the library was built without |
| support for float types. */ |
| CN_CBOR_ERR_FLOAT_NOT_SUPPORTED |
| } cn_cbor_error; |
| |
| /** |
| * Strings matching the `cn_cbor_error` conditions. |
| * |
| * @todo: turn into a function to make the type safety more clear? |
| */ |
| extern const char *cn_cbor_error_str[]; |
| |
| /** |
| * Errors |
| */ |
| typedef struct cn_cbor_errback { |
| /** The position in the input where the erorr happened */ |
| int pos; |
| /** The error, or CN_CBOR_NO_ERROR if none */ |
| cn_cbor_error err; |
| } cn_cbor_errback; |
| |
| #ifdef USE_CBOR_CONTEXT |
| |
| /** |
| * Allocate and zero out memory. `count` elements of `size` are required, |
| * as for `calloc(3)`. The `context` is the `cn_cbor_context` passed in |
| * earlier to the CBOR routine. |
| * |
| * @param[in] count The number of items to allocate |
| * @param[in] size The size of each item |
| * @param[in] context The allocation context |
| */ |
| typedef void* (*cn_calloc_func)(size_t count, size_t size, void *context); |
| |
| /** |
| * Free memory previously allocated with a context. If using a pool allocator, |
| * this function will often be a no-op, but it must be supplied in order to |
| * prevent the CBOR library from calling `free(3)`. |
| * |
| * @note: it may be that this is never needed; if so, it will be removed for |
| * clarity and speed. |
| * |
| * @param context [description] |
| * @return [description] |
| */ |
| typedef void (*cn_free_func)(void *ptr, void *context); |
| |
| /** |
| * The allocation context. |
| */ |
| typedef struct cn_cbor_context { |
| /** The pool `calloc` routine. Must allocate and zero. */ |
| cn_calloc_func calloc_func; |
| /** The pool `free` routine. Often a no-op, but required. */ |
| cn_free_func free_func; |
| /** Typically, the pool object, to be used when calling `calloc_func` |
| * and `free_func` */ |
| void *context; |
| } cn_cbor_context; |
| |
| /** When USE_CBOR_CONTEXT is defined, many functions take an extra `context` |
| * parameter */ |
| #define CBOR_CONTEXT , cn_cbor_context *context |
| /** When USE_CBOR_CONTEXT is defined, some functions take an extra `context` |
| * parameter at the beginning */ |
| #define CBOR_CONTEXT_COMMA cn_cbor_context *context, |
| |
| #else |
| |
| #define CBOR_CONTEXT |
| #define CBOR_CONTEXT_COMMA |
| |
| #endif |
| |
| /** |
| * Decode an array of CBOR bytes into structures. |
| * |
| * @param[in] buf The array of bytes to parse |
| * @param[in] len The number of bytes in the array |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The parsed CBOR structure, or NULL on error |
| */ |
| cn_cbor* cn_cbor_decode(const uint8_t *buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp); |
| |
| /** |
| * Get a value from a CBOR map that has the given string as a key. |
| * |
| * @param[in] cb The CBOR map |
| * @param[in] key The string to look up in the map |
| * @return The matching value, or NULL if the key is not found |
| */ |
| cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key); |
| |
| /** |
| * Get a value from a CBOR map that has the given integer as a key. |
| * |
| * @param[in] cb The CBOR map |
| * @param[in] key The int to look up in the map |
| * @return The matching value, or NULL if the key is not found |
| */ |
| cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key); |
| |
| /** |
| * Get the item with the given index from a CBOR array. |
| * |
| * @param[in] cb The CBOR map |
| * @param[in] idx The array index |
| * @return The matching value, or NULL if the index is invalid |
| */ |
| cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx); |
| |
| /** |
| * Free the given CBOR structure. |
| * You MUST NOT try to free a cn_cbor structure with a parent (i.e., one |
| * that is not a root in the tree). |
| * |
| * @param[in] cb The CBOR value to free. May be NULL, or a root object. |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| */ |
| void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT); |
| |
| /** |
| * Write a CBOR value and all of the child values. |
| * |
| * @param[in] buf The buffer into which to write |
| * @param[in] buf_offset The offset (in bytes) from the beginning of the buffer |
| * to start writing at |
| * @param[in] buf_size The total length (in bytes) of the buffer |
| * @param[in] cb [description] |
| * @return -1 on fail, or number of bytes written |
| */ |
| ssize_t cn_cbor_encoder_write(uint8_t *buf, |
| size_t buf_offset, |
| size_t buf_size, |
| const cn_cbor *cb); |
| |
| /** |
| * Create a CBOR map. |
| * |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created map, or NULL on error |
| */ |
| cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); |
| |
| /** |
| * Create a CBOR byte string. The data in the byte string is *not* owned |
| * by the CBOR object, so it is not freed automatically. |
| * |
| * @param[in] data The data |
| * @param[in] len The number of bytes of data |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created object, or NULL on error |
| */ |
| cn_cbor* cn_cbor_data_create(const uint8_t* data, int len |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| |
| /** |
| * Create a CBOR UTF-8 string. The data is not checked for UTF-8 correctness. |
| * The data being stored in the string is *not* owned the CBOR object, so it is |
| * not freed automatically. |
| * |
| * @note: Do NOT use this function with untrusted data. It calls strlen, and |
| * relies on proper NULL-termination. |
| * |
| * @param[in] data NULL-terminated UTF-8 string |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created object, or NULL on error |
| */ |
| cn_cbor* cn_cbor_string_create(const char* data |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| |
| /** |
| * Create a CBOR integer (either positive or negative). |
| * |
| * @param[in] value the value of the integer |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created object, or NULL on error |
| */ |
| cn_cbor* cn_cbor_int_create(int64_t value |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| |
| #ifndef CBOR_NO_FLOAT |
| /** |
| * Create a CBOR float. |
| * |
| * @param[in] value the value of the float |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created object, or NULL on error |
| */ |
| cn_cbor* cn_cbor_float_create(float value |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| |
| /** |
| * Create a CBOR double. |
| * |
| * @param[in] value the value of the double |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created object, or NULL on error |
| */ |
| cn_cbor* cn_cbor_double_create(double value |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| #endif /* CBOR_NO_FLOAT */ |
| |
| /** |
| * Put a CBOR object into a map with a CBOR object key. Duplicate checks are NOT |
| * currently performed. |
| * |
| * @param[in] cb_map The map to insert into |
| * @param[in] key The key |
| * @param[in] cb_value The value |
| * @param[out] errp Error |
| * @return True on success |
| */ |
| bool cn_cbor_map_put(cn_cbor* cb_map, |
| cn_cbor *cb_key, cn_cbor *cb_value, |
| cn_cbor_errback *errp); |
| |
| /** |
| * Put a CBOR object into a map with an integer key. Duplicate checks are NOT |
| * currently performed. |
| * |
| * @param[in] cb_map The map to insert into |
| * @param[in] key The integer key |
| * @param[in] cb_value The value |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error |
| * @return True on success |
| */ |
| bool cn_cbor_mapput_int(cn_cbor* cb_map, |
| int64_t key, cn_cbor* cb_value |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| |
| /** |
| * Put a CBOR object into a map with a string key. Duplicate checks are NOT |
| * currently performed. |
| * |
| * @note: do not call this routine with untrusted string data. It calls |
| * strlen, and requires a properly NULL-terminated key. |
| * |
| * @param[in] cb_map The map to insert into |
| * @param[in] key The string key |
| * @param[in] cb_value The value |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error |
| * @return True on success |
| */ |
| bool cn_cbor_mapput_string(cn_cbor* cb_map, |
| const char* key, cn_cbor* cb_value |
| CBOR_CONTEXT, |
| cn_cbor_errback *errp); |
| |
| /** |
| * Create a CBOR array |
| * |
| * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) |
| * @param[out] errp Error, if NULL is returned |
| * @return The created object, or NULL on error |
| */ |
| cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); |
| |
| /** |
| * Append an item to the end of a CBOR array. |
| * |
| * @param[in] cb_array The array into which to insert |
| * @param[in] cb_value The value to insert |
| * @param[out] errp Error |
| * @return True on success |
| */ |
| bool cn_cbor_array_append(cn_cbor* cb_array, |
| cn_cbor* cb_value, |
| cn_cbor_errback *errp); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* CN_CBOR_H */ |