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