#ifndef _EMPACK_H_ #define _EMPACK_H_ #include /** Pairing struct for maps */ typedef struct empack_map_pair_struct empack_map_pair_t; /** Map struct for all MAP type values */ typedef struct empack_map_struct empack_map_t; /** Array struct for all ARRAY type values */ typedef struct empack_array_struct empack_array_t; /** String struct for all STR type values */ typedef struct empack_str_struct empack_str_t; /** Binary struct for all BIN type values */ typedef struct empack_bin_struct empack_bin_t; /** Extension struct for all EXT type values */ typedef struct empack_ext_struct empack_ext_t; /** Object struct for all types of MessagePack objects */ typedef struct empack_obj_struct empack_obj_t; /** Empack struct for constructing a MessagePack tree structure */ typedef struct empack_struct empack_t; /** * Enum of the first bytes for each msgpack type. For types with a range of * values that could be the first byte, the lowest is used */ typedef enum empack_type_enum { /** Positive FIXINT, stored in `empack_obj_t::val.uint8` */ EMPACK_TYPE_POS_FIXINT = 0x00, /** FIXMAP, enum field `val.map` */ EMPACK_TYPE_FIXMAP = 0x80, /** FIXARRAY, enum field `val.map` */ EMPACK_TYPE_FIXARRAY = 0x90, /** FIXSTR, enum field `val.str` */ EMPACK_TYPE_FIXSTR = 0xa0, /** NIL, no value */ EMPACK_TYPE_NIL = 0xc0, /** * Special error type reserved for a type parsing error. This type is never * used in the Msgpack spec. */ EMPACK_TYPE_ERROR = 0xc1, /** FALSE, no value */ EMPACK_TYPE_FALSE = 0xc2, /** TRUE, no value */ EMPACK_TYPE_TRUE = 0xc3, /** BIN8, enum field `val.bin` */ EMPACK_TYPE_BIN8 = 0xc4, /** BIN16, enum field `val.bin` */ EMPACK_TYPE_BIN16 = 0xc5, /** BIN32, enum field `val.bin` */ EMPACK_TYPE_BIN32 = 0xc6, /** EXT8, enum field `val.ext` */ EMPACK_TYPE_EXT8 = 0xc7, /** EXT16, enum field `val.ext` */ EMPACK_TYPE_EXT16 = 0xc8, /** EXT32, enum field `val.ext` */ EMPACK_TYPE_EXT32 = 0xc9, /** FLOAT32, enum field `val.float32` */ EMPACK_TYPE_FLOAT32 = 0xca, /** FLOAT64, enum field `val.float64` */ EMPACK_TYPE_FLOAT64 = 0xcb, /** UINT8, enum field `val.uint8` */ EMPACK_TYPE_UINT8 = 0xcc, /** UINT16, enum field `val.uint16` */ EMPACK_TYPE_UINT16 = 0xcd, /** UINT32, enum field `val.uint32` */ EMPACK_TYPE_UINT32 = 0xce, /** UINT64, enum field `val.uint64` */ EMPACK_TYPE_UINT64 = 0xcf, /** INT8, enum field `val.int8` */ EMPACK_TYPE_INT8 = 0xd0, /** INT16, enum field `val.int16` */ EMPACK_TYPE_INT16 = 0xd1, /** INT32, enum field `val.int32` */ EMPACK_TYPE_INT32 = 0xd2, /** INT64, enum field `val.int64` */ EMPACK_TYPE_INT64 = 0xd3, /** FIXEXT1, enum field `val.ext` */ EMPACK_TYPE_FIXEXT1 = 0xd4, /** FIXEXT2, enum field `val.ext` */ EMPACK_TYPE_FIXEXT2 = 0xd5, /** FIXEXT4, enum field `val.ext` */ EMPACK_TYPE_FIXEXT4 = 0xd6, /** FIXEXT8, enum field `val.ext` */ EMPACK_TYPE_FIXEXT8 = 0xd7, /** FIXEXT16, enum field `val.ext` */ EMPACK_TYPE_FIXEXT16 = 0xd8, /** STR8, enum field `val.str */ EMPACK_TYPE_STR8 = 0xd9, /** STR16, enum field `val.str */ EMPACK_TYPE_STR16 = 0xda, /** STR32, enum field `val.str */ EMPACK_TYPE_STR32 = 0xdb, /** ARRAY16, enum field `val.array` */ EMPACK_TYPE_ARRAY16 = 0xdc, /** ARRAY32, enum field `val.array` */ EMPACK_TYPE_ARRAY32 = 0xdd, /** MAP16, enum field `val.map` */ EMPACK_TYPE_MAP16 = 0xde, /** MAP32, enum field `val.map` */ EMPACK_TYPE_MAP32 = 0xdf, /** Negative FIXINT, enum field `val.int8` */ EMPACK_TYPE_NEG_FIXINT = 0xe0, } empack_type_e; /** Enum parsing status return codes */ typedef enum empack_status_enum { /** Parsing is completed with no errors */ EMPACK_STATUS_COMPLETE = 0, /** No errors in parsing, but the Msgpack supplied is incomplete */ EMPACK_STATUS_WANT_MORE, /** Parsing completed, but extra data was supplied and not parsed */ EMPACK_STATUS_EXTRA, /** * Ran out of arena memory, the empack->arena_used value will show the * amount of memory required to fully parse the supplied Msgpack buffer */ EMPACK_STATUS_NOMEM, /** Generic error while parsing */ EMPACK_STATUS_ERROR, } empack_status_e; struct empack_map_struct { /** List of key-value pairs in the map */ empack_map_pair_t *pairs; /** Number of key-value pairs expected to be in the map */ uint32_t pair_count; /** Parsed count utilized in tree traversal */ uint32_t pairs_parsed; }; struct empack_array_struct { /** List of the objects in the array */ empack_obj_t *objects; /** Number of objects expected to be in the array */ uint32_t object_count; /** Parsed count utilized in tree traversal */ uint32_t objects_parsed; }; struct empack_str_struct { /** Data value, points into the originally supplied Msgpack buffer */ const char *data; /** Expected size of the string buffer */ uint32_t size; }; struct empack_bin_struct { /** Data value, points into the originally supplied Msgpack buffer */ const void *data; /** Expected size of the buffer */ uint32_t size; }; struct empack_ext_struct { /** Data value, points into the originally supplied Msgpack buffer */ const void *data; /** Size of the buffer */ uint32_t size; /** Type value for the EXT object */ uint8_t type; }; struct empack_obj_struct { empack_type_e type; union { /** Union value valid for all MAP type data */ empack_map_t map; /** Union value valid for all ARRAY type data */ empack_array_t array; /** Union value valid for all STR type data */ empack_str_t str; /** Union value valid for all BIN type data */ empack_bin_t bin; /** Union value valid for all EXT type data */ empack_ext_t ext; float float32; double float64; uint8_t uint8; uint16_t uint16; uint32_t uint32; uint64_t uint64; int8_t int8; int16_t int16; int32_t int32; int64_t int64; } val; /** * If this object is in a MAP or ARRAY, this is a pointer to the parent * object. Needed for parsing purposes, and useful for tree traversal after * parsing. NULL if no parent is present. */ empack_obj_t *parent; /** * Object that comes immediately after this one in the original Msgpack * buffer, NULL if last object */ empack_obj_t *next; }; struct empack_map_pair_struct { /** Key object for this pair */ empack_obj_t key; /** Value object for this pair */ empack_obj_t value; }; struct empack_struct { /** Root object of the Msgpack object tree, filled out during parsing */ empack_obj_t root; /** Memory arena empack can use to construct the object tree */ void *arena; /** Size of the memory arena */ uint32_t arena_sz; /** How much of the memory arena is used */ uint32_t arena_used; }; /** Macro for whether the given type is a map */ #define EMPACK_IS_MAP(type) ((type == EMPACK_TYPE_FIXMAP) || \ (type == EMPACK_TYPE_MAP16) || \ (type == EMPACK_TYPE_MAP32)) /** Macro for whether the given type is an array */ #define EMPACK_IS_ARRAY(type) ((type == EMPACK_TYPE_FIXARRAY) || \ (type == EMPACK_TYPE_ARRAY16) || \ (type == EMPACK_TYPE_ARRAY16)) /** * Initialize an empack struct, allowing it to be used for parsing. Calling this * on a previously initialized empack struct will effectively reset it. * * The arena memory supplied must be valid for the entire lifetime of the empack * struct. * * @param empack Empack struct to initialize * @param arena Memory arena empack will use for storing Msgpack object tree information * @param arena_sz Size of the memory arena */ void empack_init(empack_t *empack, void *arena, uint32_t arena_sz); /** * Parse the provided Msgpack data. Note that the resulting object tree in the * empack struct may point into the supplied buffer for certain objects such as * BIN types. * * Spec for reference: https://github.com/msgpack/msgpack/blob/master/spec.md * * @param empack Empack struct, must be initialized by empack_init * @param msgpack Msgpack buffer to parse * @param len Size of the Msgpack buffer * * @returns An EMPACK_STATUS_* value */ empack_status_e empack_parse(empack_t *empack, const void *msgpack, uint32_t len); /** * Parse a singular Msgpack object, useful for use cases where the Msgpack data * must be streamed or the caller does not want to allocate a memory arena. * * Note that for MAP and ARRAY types, the object pointers to child objects will * not be allocated and set to NULL. * * @param object Empack object struct to fill out * @param msgpack Msgpack buffer to parse * @param len Length of the Msgpack buffer, set on return to the number of bytes * processed * * @returns An EMPACK_STATUS_* value */ empack_status_e empack_parse_one(empack_obj_t *object, const void *msgpack, uint32_t *len); /** * Given an empack struct that has successfully been called with empack_parse, * print a JSON formatted string via the supplied print function. An optional * indent string can be supplied for formatting, if NULL the JSON will be * minified. * * Note that not all MessagePack trees can transform into valid JSON, such as * the BIN/EXT data types, or using non-string values as keys in maps. * * @param empack Empack struct to print * @param print_func Print function to be called for outputting characters * @param arg User argument for print_func * @param indent Optional indent string * * @returns Number of characters printed, excluding the NULL terminator */ uint32_t empack_print(empack_t *empack, void (*print_func)(const char *buf, uint32_t buflen, void *arg), void *arg, const char *indent); #endif /* _EMPACK_H_ */