Home | History | Annotate | Download | only in cn-cbor
      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