Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
cn-cbor.h
Go to the documentation of this file.
00001 /** 00002 * \file 00003 * \brief 00004 * CBOR parsing 00005 */ 00006 00007 #ifndef CN_CBOR_H 00008 #define CN_CBOR_H 00009 00010 #ifdef __cplusplus 00011 extern "C" { 00012 #endif 00013 00014 //typedef int ssize_t; 00015 00016 #ifdef EMACS_INDENTATION_HELPER 00017 } /* Duh. */ 00018 #endif 00019 00020 #include <stdbool.h> 00021 #include <stdint.h> 00022 #include <stdio.h> 00023 00024 //typedef ssize_t int; 00025 //#include <unistd.h> 00026 00027 /** 00028 * All of the different kinds of CBOR values. 00029 */ 00030 typedef enum cn_cbor_type { 00031 /** false */ 00032 CN_CBOR_FALSE, 00033 /** true */ 00034 CN_CBOR_TRUE, 00035 /** null */ 00036 CN_CBOR_NULL, 00037 /** undefined */ 00038 CN_CBOR_UNDEF, 00039 /** Positive integers */ 00040 CN_CBOR_UINT, 00041 /** Negative integers */ 00042 CN_CBOR_INT, 00043 /** Byte string */ 00044 CN_CBOR_BYTES, 00045 /** UTF-8 string */ 00046 CN_CBOR_TEXT, 00047 /** Byte string, in chunks. Each chunk is a child. */ 00048 CN_CBOR_BYTES_CHUNKED, 00049 /** UTF-8 string, in chunks. Each chunk is a child */ 00050 CN_CBOR_TEXT_CHUNKED, 00051 /** Array of CBOR values. Each array element is a child, in order */ 00052 CN_CBOR_ARRAY, 00053 /** Map of key/value pairs. Each key and value is a child, alternating. */ 00054 CN_CBOR_MAP, 00055 /** Tag describing the next value. The next value is the single child. */ 00056 CN_CBOR_TAG, 00057 /** Simple value, other than the defined ones */ 00058 CN_CBOR_SIMPLE, 00059 /** Doubles, floats, and half-floats */ 00060 CN_CBOR_DOUBLE, 00061 /** An error has occurred */ 00062 CN_CBOR_INVALID 00063 } cn_cbor_type; 00064 00065 /** 00066 * Flags used during parsing. Not useful for consumers of the 00067 * `cn_cbor` structure. 00068 */ 00069 typedef enum cn_cbor_flags { 00070 /** The count field will be used for parsing */ 00071 CN_CBOR_FL_COUNT = 1, 00072 /** An indefinite number of children */ 00073 CN_CBOR_FL_INDEF = 2, 00074 /** Not used yet; the structure must free the v.str pointer when the 00075 structure is freed */ 00076 CN_CBOR_FL_OWNER = 0x80, /* of str */ 00077 } cn_cbor_flags; 00078 00079 // FIXME: These could be used in the future instead of type and flags in struct cn_cbor (will make the sizeof(cn_cbor) 8 bytes less) 00080 //#define CN_CBOR_TYPE(pCbor) (pCbor->enums & 0x0f) 00081 //#define CN_CBOR_FLAGS(pCbor) (pCbor->enums & 0xf0) 00082 00083 /** 00084 * A CBOR value 00085 */ 00086 00087 typedef struct cn_cbor { 00088 /** The type of value */ 00089 cn_cbor_type type; 00090 /** Flags used at parse time */ 00091 cn_cbor_flags flags; 00092 /** Data associated with the value; different branches of the union are 00093 used depending on the `type` field. */ 00094 union { 00095 /** CN_CBOR_BYTES */ 00096 const uint8_t* bytes; 00097 /** CN_CBOR_TEXT */ 00098 const char* str; 00099 /** CN_CBOR_INT */ 00100 int64_t sint; 00101 /** CN_CBOR_UINT */ 00102 uint64_t uint; 00103 /** CN_CBOR_DOUBLE */ 00104 double dbl; 00105 /** for use during parsing */ 00106 unsigned long count; 00107 } v; /* TBD: optimize immediate */ 00108 /** Number of children. 00109 * @note: for maps, this is 2x the number of entries */ 00110 int length; 00111 00112 // FIXME: This could be used in the future instead of type and flags in struct cn_cbor (will make the sizeof(cn_cbor) 8 bytes less) 00113 //uint8_t enums; 00114 00115 /** The first child value */ 00116 struct cn_cbor* first_child; 00117 /** The last child value */ 00118 struct cn_cbor* last_child; 00119 /** The sibling after this one, or NULL if this is the last */ 00120 struct cn_cbor* next; 00121 /** The parent of this value, or NULL if this is the root */ 00122 struct cn_cbor* parent; 00123 } cn_cbor; 00124 00125 /** 00126 * All of the different kinds of errors 00127 */ 00128 typedef enum cn_cbor_error { 00129 /** No error has occurred */ 00130 CN_CBOR_NO_ERROR, 00131 /** More data was expected while parsing */ 00132 CN_CBOR_ERR_OUT_OF_DATA, 00133 /** Some extra data was left over at the end of parsing */ 00134 CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED, 00135 /** A map should be alternating keys and values. A break was found 00136 when a value was expected */ 00137 CN_CBOR_ERR_ODD_SIZE_INDEF_MAP, 00138 /** A break was found where it wasn't expected */ 00139 CN_CBOR_ERR_BREAK_OUTSIDE_INDEF, 00140 /** Indefinite encoding works for bstrs, strings, arrays, and maps. 00141 A different major type tried to use it. */ 00142 CN_CBOR_ERR_MT_UNDEF_FOR_INDEF, 00143 /** Additional Information values 28-30 are reserved */ 00144 CN_CBOR_ERR_RESERVED_AI, 00145 /** A chunked encoding was used for a string or bstr, and one of the elements 00146 wasn't the expected (string/bstr) type */ 00147 CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING, 00148 /** An invalid parameter was passed to a function */ 00149 CN_CBOR_ERR_INVALID_PARAMETER, 00150 /** Allocation failed */ 00151 CN_CBOR_ERR_OUT_OF_MEMORY, 00152 /** A float was encountered during parse but the library was built without 00153 support for float types. */ 00154 CN_CBOR_ERR_FLOAT_NOT_SUPPORTED, 00155 /** Encoder was unable to encode the cn_cbor object that was provided */ 00156 CN_CBOR_ERR_ENCODER 00157 } cn_cbor_error; 00158 00159 /** 00160 * Strings matching the `cn_cbor_error` conditions. 00161 * 00162 * @todo: turn into a function to make the type safety more clear? 00163 */ 00164 extern const char *cn_cbor_error_str[]; 00165 00166 /** 00167 * Errors 00168 */ 00169 typedef struct cn_cbor_errback { 00170 /** The position in the input where the erorr happened */ 00171 int pos; 00172 /** The error, or CN_CBOR_NO_ERROR if none */ 00173 cn_cbor_error err; 00174 } cn_cbor_errback; 00175 00176 #ifdef USE_CBOR_CONTEXT 00177 00178 00179 /** 00180 * Allocate and zero out memory. `count` elements of `size` are required, 00181 * as for `calloc(3)`. The `context` is the `cn_cbor_context` passed in 00182 * earlier to the CBOR routine. 00183 * 00184 * @param[in] count The number of items to allocate 00185 * @param[in] size The size of each item 00186 * @param[in] context The allocation context 00187 */ 00188 typedef void* (*cn_calloc_func)(size_t count, size_t size, void *context); 00189 00190 /** 00191 * Free memory previously allocated with a context. If using a pool allocator, 00192 * this function will often be a no-op, but it must be supplied in order to 00193 * prevent the CBOR library from calling `free(3)`. 00194 * 00195 * @note: it may be that this is never needed; if so, it will be removed for 00196 * clarity and speed. 00197 * 00198 * @param context [description] 00199 * @return [description] 00200 */ 00201 typedef void (*cn_free_func)(void *ptr, void *context); 00202 00203 /** 00204 * The allocation context. 00205 */ 00206 typedef struct cn_cbor_context { 00207 /** The pool `calloc` routine. Must allocate and zero. */ 00208 cn_calloc_func calloc_func; 00209 /** The pool `free` routine. Often a no-op, but required. */ 00210 cn_free_func free_func; 00211 /** Typically, the pool object, to be used when calling `calloc_func` 00212 * and `free_func` */ 00213 void *context; 00214 } cn_cbor_context; 00215 00216 extern cn_cbor_context *cbor_context; 00217 00218 /** When USE_CBOR_CONTEXT is defined, many functions take an extra `context` 00219 * parameter */ 00220 #define CBOR_CONTEXT , cn_cbor_context *cbor_context 00221 /** When USE_CBOR_CONTEXT is defined, some functions take an extra `context` 00222 * parameter at the beginning */ 00223 #define CBOR_CONTEXT_COMMA cn_cbor_context *cbor_context, 00224 /** When USE_CBOR_CONTEXT is defined, some functions take a `context` 00225 * parameter, as the only argument */ 00226 #define CBOR_CONTEXT_NO_COMMA cn_cbor_context *cbor_context 00227 00228 /** The following two defines are used by caller as arguments for the 00229 * function that is being called - to use context*/ 00230 #define CBOR_CONTEXT_PARAM , cbor_context 00231 #define CBOR_CONTEXT_PARAM_COMMA cbor_context, 00232 00233 /** The following two defines are used by caller as arguments for the 00234 * function that is being called - to force use of LIBC allocation instead of pool*/ 00235 #define CBOR_CONTEXT_NULL , NULL 00236 #define CBOR_CONTEXT_NULL_COMMA NULL, 00237 00238 00239 #else 00240 00241 #define CBOR_CONTEXT 00242 #define CBOR_CONTEXT_COMMA 00243 #define CBOR_CONTEXT_NO_COMMA void 00244 #define CBOR_CONTEXT_PARAM 00245 #define CBOR_CONTEXT_PARAM_COMMA 00246 #define CBOR_CONTEXT_NULL 00247 #define CBOR_CONTEXT_NULL_COMMA 00248 00249 #endif 00250 00251 /** 00252 * Decode an array of CBOR bytes into structures. 00253 * 00254 * @param[in] buf The array of bytes to parse 00255 * @param[in] len The number of bytes in the array 00256 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00257 * @param[out] errp Error, if NULL is returned 00258 * @return The parsed CBOR structure, or NULL on error 00259 */ 00260 cn_cbor* cn_cbor_decode(const uint8_t *buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp); 00261 00262 /** 00263 * Get a value from a CBOR map that has the given string as a key. 00264 * 00265 * @param[in] cb The CBOR map 00266 * @param[in] key The string to look up in the map 00267 * @return The matching value, or NULL if the key is not found 00268 */ 00269 cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key); 00270 00271 /** 00272 * Get a value from a CBOR map that has the given integer as a key. 00273 * 00274 * @param[in] cb The CBOR map 00275 * @param[in] key The int to look up in the map 00276 * @return The matching value, or NULL if the key is not found 00277 */ 00278 cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key); 00279 00280 /** 00281 * Get the item with the given index from a CBOR array. 00282 * 00283 * @param[in] cb The CBOR map 00284 * @param[in] idx The array index 00285 * @return The matching value, or NULL if the index is invalid 00286 */ 00287 cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx); 00288 00289 /** 00290 * Free the given CBOR structure. 00291 * You MUST NOT try to free a cn_cbor structure with a parent (i.e., one 00292 * that is not a root in the tree). 00293 * 00294 * @param[in] cb The CBOR value to free. May be NULL, or a root object. 00295 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00296 */ 00297 void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT); 00298 00299 /** 00300 * Get the size of the buffer that must be provided to cn_cbor_encoder_write(). 00301 * This is the size of the CBOR that will be encoded. 00302 * 00303 * @param[in] cb Pointer to a cn_cbor structure, which the user wishes to encode. 00304 * @param[out] err Error, if -1 is returned. 00305 * @return -1 on fail, or number size of the allocated buffer containing the encoded data. 00306 */ 00307 00308 int cn_cbor_get_encoded_size(const cn_cbor *cb, cn_cbor_errback *err); 00309 00310 /** 00311 * Write a CBOR value and all of the child values. 00312 * Allocates a buffer of the correct size and fills it with the encoded CBOR. 00313 * User must free the buffer. 00314 * 00315 * @param[in] cb Pointer to a cn_cbor structure, which the user wishes to encode. 00316 * @param[out] bufOut Pointer a buffer which will be filled with the encoded data. 00317 * @param[in] bufSize Size of the provided buffer in bytes. 00318 * @param[out] err Error, if -1 is returned. 00319 * @return -1 on fail, or number encoded bytes written to the provided buffer. 00320 */ 00321 00322 int cn_cbor_encoder_write(const cn_cbor *cb, uint8_t *bufOut, int bufSize, cn_cbor_errback *err); 00323 00324 /** 00325 * Create a CBOR map. 00326 * 00327 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00328 * @param[out] errp Error, if NULL is returned 00329 * @return The created map, or NULL on error 00330 */ 00331 cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); 00332 00333 /** 00334 * Create a CBOR byte string. The data in the byte string is *not* owned 00335 * by the CBOR object, so it is not freed automatically. 00336 * 00337 * @param[in] data The data 00338 * @param[in] len The number of bytes of data 00339 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00340 * @param[out] errp Error, if NULL is returned 00341 * @return The created object, or NULL on error 00342 */ 00343 cn_cbor* cn_cbor_data_create(const uint8_t* data, int len 00344 CBOR_CONTEXT, 00345 cn_cbor_errback *errp); 00346 00347 /** 00348 * Create a CBOR UTF-8 string. The data is not checked for UTF-8 correctness. 00349 * The data being stored in the string is *not* owned the CBOR object, so it is 00350 * not freed automatically. 00351 * 00352 * @note: Do NOT use this function with untrusted data. It calls strlen, and 00353 * relies on proper NULL-termination. 00354 * 00355 * @param[in] data NULL-terminated UTF-8 string 00356 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00357 * @param[out] errp Error, if NULL is returned 00358 * @return The created object, or NULL on error 00359 */ 00360 cn_cbor* cn_cbor_string_create(const char* data 00361 CBOR_CONTEXT, 00362 cn_cbor_errback *errp); 00363 00364 /** 00365 * Create a CBOR integer (either positive or negative). 00366 * 00367 * @param[in] value the value of the integer 00368 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00369 * @param[out] errp Error, if NULL is returned 00370 * @return The created object, or NULL on error 00371 */ 00372 cn_cbor* cn_cbor_int_create(int64_t value 00373 CBOR_CONTEXT, 00374 cn_cbor_errback *errp); 00375 00376 00377 /** 00378 * Create a CBOR unsigned integer ( positive ). 00379 * 00380 * @param[in] value the value of the unsigned integer 00381 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00382 * @param[out] errp Error, if NULL is returned 00383 * @return The created object, or NULL on error 00384 */ 00385 cn_cbor* cn_cbor_uint_create(uint64_t value 00386 CBOR_CONTEXT, 00387 cn_cbor_errback *errp); 00388 00389 /** 00390 * Put a CBOR object into a map with a CBOR object key. Duplicate checks are NOT 00391 * currently performed. 00392 * 00393 * @param[in] cb_map The map to insert into 00394 * @param[in] key The key 00395 * @param[in] cb_value The value 00396 * @param[out] errp Error 00397 * @return True on success 00398 */ 00399 bool cn_cbor_map_put(cn_cbor* cb_map, 00400 cn_cbor *cb_key, cn_cbor *cb_value, 00401 cn_cbor_errback *errp); 00402 00403 /** 00404 * Put a CBOR object into a map with an integer key. Duplicate checks are NOT 00405 * currently performed. 00406 * 00407 * @param[in] cb_map The map to insert into 00408 * @param[in] key The integer key 00409 * @param[in] cb_value The value 00410 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00411 * @param[out] errp Error 00412 * @return True on success 00413 */ 00414 bool cn_cbor_mapput_int(cn_cbor* cb_map, 00415 int64_t key, cn_cbor* cb_value 00416 CBOR_CONTEXT, 00417 cn_cbor_errback *errp); 00418 00419 /** 00420 * Put a CBOR object into a map with a string key. Duplicate checks are NOT 00421 * currently performed. 00422 * 00423 * @note: do not call this routine with untrusted string data. It calls 00424 * strlen, and requires a properly NULL-terminated key. 00425 * 00426 * @param[in] cb_map The map to insert into 00427 * @param[in] key The string key 00428 * @param[in] cb_value The value 00429 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00430 * @param[out] errp Error 00431 * @return True on success 00432 */ 00433 bool cn_cbor_mapput_string(cn_cbor* cb_map, 00434 const char* key, cn_cbor* cb_value 00435 CBOR_CONTEXT, 00436 cn_cbor_errback *errp); 00437 00438 /** 00439 * Create a CBOR array 00440 * 00441 * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) 00442 * @param[out] errp Error, if NULL is returned 00443 * @return The created object, or NULL on error 00444 */ 00445 cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); 00446 00447 /** 00448 * Append an item to the end of a CBOR array. 00449 * 00450 * @param[in] cb_array The array into which to insert 00451 * @param[in] cb_value The value to insert 00452 * @param[out] errp Error 00453 * @return True on success 00454 */ 00455 bool cn_cbor_array_append(cn_cbor* cb_array, 00456 cn_cbor* cb_value, 00457 cn_cbor_errback *errp); 00458 00459 #ifdef USE_CBOR_CONTEXT 00460 00461 // The maximum number of CBOR objects in an allocated pool. 00462 #define MAX_SIZE_POOL_IN_CBORS 64 00463 00464 /** 00465 * Init a new cn_cbor_context. 00466 * This will dynamically allocate a pool of cn_cbor objects and must be freed by calling cn_cbor_free_context. 00467 * FIXME: The created context is currently stored as a global in cn-cbor.c for easy access and convenience. 00468 * This means only one CBOR context can be used at a time and is prone to errors if we are not careful. 00469 * In the future we will probably want to init a context and and pass it on all the way to the cn_cbor functions that need access to it, Instead of using a global. 00470 * This will also allow us to use several contexts at a time and run multi-threaded. 00471 * 00472 * @param[in] num_of_cbors_in_pool The number of cn_cbor object in the pool. The size of the dynamically allocated pool will be num_of_cbors_in_pool * sizeof(cn_cbor) 00473 * 00474 * @return A pointer to the created context, or NULL in case of error 00475 */ 00476 cn_cbor_context *cn_cbor_init_context(size_t num_of_cbors_in_pool); 00477 00478 /** 00479 * Release the resources of a cn_cbor_context. 00480 * Releases the dynamically allocated pool. if either ctx is NULL or the pool is NULL, 00481 * then the function will do nothing. This should never happen, unless user committed an error. 00482 * The function does not return anything to conform with standard freeing practices. 00483 * 00484 * @param[in] ctx Pointer to the cn_cbor_context object which points to the memory pool we wish to free 00485 * 00486 */ 00487 void cn_cbor_free_context(cn_cbor_context *ctx); 00488 00489 #ifdef USE_CBOR_CONTEXT_STATS 00490 00491 /** 00492 * Print stats of the memory allocations of the CBOR library. 00493 */ 00494 void cn_cbor_context_print_stats(void); 00495 00496 /** 00497 * Resets the stats of the memory allocations of the CBOR library. 00498 */ 00499 void cn_cbor_context_reset_stats(void); 00500 00501 #else 00502 #define cn_cbor_context_print_stats() 00503 #define cn_cbor_context_reset_stats() 00504 #endif // USE_CBOR_CONTEXT_STATS 00505 00506 #endif // USE_CBOR_CONTEXT 00507 00508 00509 #ifdef __cplusplus 00510 } 00511 #endif 00512 00513 #endif /* CN_CBOR_H */
Generated on Tue Jul 12 2022 19:01:33 by 1.7.2