blob: 28a22c68703c87b446cde4e7c3a38e7c56baca70 [file] [log] [blame]
/**
* \file
* \brief
* CBOR parsing
*/
#ifndef CN_CBOR_H
#define CN_CBOR_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef EMACS_INDENTATION_HELPER
} /* Duh. */
#endif
/**
* All of the different kinds of CBOR values.
*/
typedef enum cn_cbor_type {
/** null */
CN_CBOR_NULL,
/** false */
CN_CBOR_FALSE,
/** true */
CN_CBOR_TRUE,
/** 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,
/** 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, CN_CBOR_TEXT */
const char* str;
/** CN_CBOR_INT */
long sint;
/** CN_CBOR_UINT */
unsigned long uint;
/** CN_CBOR_DOUBLE */
double dbl;
/** 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
} cn_cbor_error;
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
typedef void* (*cn_alloc_func)(size_t count, size_t size, void *context);
typedef void (*cn_free_func)(void *ptr, void *context);
typedef struct cn_cbor_context {
cn_alloc_func calloc_func;
cn_free_func free_func;
void *context;
} cn_cbor_context;
#define CN_CALLOC(ctx) ((ctx) && (ctx)->calloc_func) ? \
(ctx)->calloc_func(1, sizeof(cn_cbor), (ctx)->context) : \
calloc(1, sizeof(cn_cbor));
#define CN_FREE(ptr, ctx) ((ctx) && (ctx)->free_func) ? \
(ctx)->free_func((ptr), (ctx)->context) : \
free((ptr));
#define CBOR_CONTEXT , cn_cbor_context *context
#define CBOR_CONTEXT_COMMA cn_cbor_context *context,
#else
#define CBOR_CONTEXT
#define CBOR_CONTEXT_COMMA
#ifndef CN_CALLOC
#define CN_CALLOC calloc(1, sizeof(cn_cbor))
#endif
#ifndef CN_FREE
#define CN_FREE free
#endif
#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] 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
*/
const cn_cbor* cn_cbor_decode(const unsigned char* 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
*/
const 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
*/
const 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
*/
const cn_cbor* cn_cbor_index(const cn_cbor* cb, int idx);
/**
* Free the given CBOR structure.
*
* @param[in] cb The CBOR value to free
* @param[in] context Allocation context (only if USE_CBOR_CONTEXT is defined)
*/
void cn_cbor_free(const cn_cbor* cb CBOR_CONTEXT);
#ifdef __cplusplus
}
#endif
#endif /* CN_CBOR_H */