• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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