/* * sfparse * * Copyright (c) 2023 sfparse contributors * Copyright (c) 2019 nghttp3 contributors * Copyright (c) 2015 nghttp2 contributors * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef SFPARSE_H #define SFPARSE_H /* Define WIN32 when build target is Win32 API (borrowed from libcurl) */ #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) # define WIN32 #endif #ifdef __cplusplus extern "C" { #endif #if defined(_MSC_VER) && (_MSC_VER < 1800) /* MSVC < 2013 does not have inttypes.h because it is not C99 compliant. See compiler macros and version number in https://sourceforge.net/p/predef/wiki/Compilers/ */ # include #else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ # include #endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ #include #include /** * @enum * * :type:`sf_type` defines value type. */ typedef enum sf_type { /** * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. */ SF_TYPE_BOOLEAN, /** * :enum:`SF_TYPE_INTEGER` indicates integer type. */ SF_TYPE_INTEGER, /** * :enum:`SF_TYPE_DECIMAL` indicates decimal type. */ SF_TYPE_DECIMAL, /** * :enum:`SF_TYPE_STRING` indicates string type. */ SF_TYPE_STRING, /** * :enum:`SF_TYPE_TOKEN` indicates token type. */ SF_TYPE_TOKEN, /** * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. */ SF_TYPE_BYTESEQ, /** * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. */ SF_TYPE_INNER_LIST, /** * :enum:`SF_TYPE_DATE` indicates date type. */ SF_TYPE_DATE } sf_type; /** * @macro * * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has * occurred, and it is not possible to continue the processing. */ #define SF_ERR_PARSE_ERROR -1 /** * @macro * * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. * The context of this error varies depending on the function that * returns this error code. */ #define SF_ERR_EOF -2 /** * @struct * * :type:`sf_vec` stores sequence of bytes. */ typedef struct sf_vec { /** * :member:`base` points to the beginning of the sequence of bytes. */ uint8_t *base; /** * :member:`len` is the number of bytes contained in this sequence. */ size_t len; } sf_vec; /** * @macro * * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. */ #define SF_VALUE_FLAG_NONE 0x0u /** * @macro * * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string * contains escaped character(s). */ #define SF_VALUE_FLAG_ESCAPED_STRING 0x1u /** * @struct * * :type:`sf_decimal` contains decimal value. */ typedef struct sf_decimal { /** * :member:`numer` contains numerator of the decimal value. */ int64_t numer; /** * :member:`denom` contains denominator of the decimal value. */ int64_t denom; } sf_decimal; /** * @struct * * :type:`sf_value` stores a Structured Field item. For Inner List, * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order * to read the items contained in an inner list, call * `sf_parser_inner_list`. */ typedef struct sf_value { /** * :member:`type` is the type of the value contained in this * particular object. */ sf_type type; /** * :member:`flags` is bitwise OR of one or more of * :macro:`SF_VALUE_FLAG_* `. */ uint32_t flags; /** * @anonunion_start * * @sf_value_value */ union { /** * :member:`boolean` contains boolean value if :member:`type` == * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 * indicates false. */ int boolean; /** * :member:`integer` contains integer value if :member:`type` is * either :enum:`sf_type.SF_TYPE_INTEGER` or * :enum:`sf_type.SF_TYPE_DATE`. */ int64_t integer; /** * :member:`decimal` contains decimal value if :member:`type` == * :enum:`sf_type.SF_TYPE_DECIMAL`. */ sf_decimal decimal; /** * :member:`vec` contains sequence of bytes if :member:`type` is * either :enum:`sf_type.SF_TYPE_STRING`, * :enum:`sf_type.SF_TYPE_TOKEN`, or * :enum:`sf_type.SF_TYPE_BYTESEQ`. * * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or * more escaped characters if :member:`flags` has * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the * string, use `sf_unescape`. * * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 * encoded string. To decode this byte string, use * `sf_base64decode`. * * If :member:`vec.len ` == 0, :member:`vec.base * ` is guaranteed to be NULL. */ sf_vec vec; /** * @anonunion_end */ }; } sf_value; /** * @struct * * :type:`sf_parser` is the Structured Field Values parser. Use * `sf_parser_init` to initialize it. */ typedef struct sf_parser { /* all fields are private */ const uint8_t *pos; const uint8_t *end; uint32_t state; } sf_parser; /** * @function * * `sf_parser_init` initializes |sfp| with the given buffer pointed by * |data| of length |datalen|. */ void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); /** * @function * * `sf_parser_param` reads a parameter. If this function returns 0, * it stores parameter key and value in |dest_key| and |dest_value| * respectively, if they are not NULL. * * This function does no effort to find duplicated keys. Same key may * be reported more than once. * * Caller should keep calling this function until it returns negative * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have * read, and caller can continue to read rest of the values. If it * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error * while parsing field value. */ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); /** * @function * * `sf_parser_dict` reads the next dictionary key and value pair. If * this function returns 0, it stores the key and value in |dest_key| * and |dest_value| respectively, if they are not NULL. * * Caller can optionally read parameters attached to the pair by * calling `sf_parser_param`. * * This function does no effort to find duplicated keys. Same key may * be reported more than once. * * Caller should keep calling this function until it returns negative * error code. If it returns :macro:`SF_ERR_EOF`, all key and value * pairs have been read, and there is nothing left to read. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`SF_ERR_EOF` * All values in the dictionary have read. * :macro:`SF_ERR_PARSE_ERROR` * It encountered fatal error while parsing field value. */ int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); /** * @function * * `sf_parser_list` reads the next list item. If this function * returns 0, it stores the item in |dest| if it is not NULL. * * Caller can optionally read parameters attached to the item by * calling `sf_parser_param`. * * Caller should keep calling this function until it returns negative * error code. If it returns :macro:`SF_ERR_EOF`, all values in the * list have been read, and there is nothing left to read. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`SF_ERR_EOF` * All values in the list have read. * :macro:`SF_ERR_PARSE_ERROR` * It encountered fatal error while parsing field value. */ int sf_parser_list(sf_parser *sfp, sf_value *dest); /** * @function * * `sf_parser_item` reads a single item. If this function returns 0, * it stores the item in |dest| if it is not NULL. * * This function is only used for the field value that consists of a * single item. * * Caller can optionally read parameters attached to the item by * calling `sf_parser_param`. * * Caller should call this function again to make sure that there is * nothing left to read. If this 2nd function call returns * :macro:`SF_ERR_EOF`, all data have been processed successfully. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`SF_ERR_EOF` * There is nothing left to read. * :macro:`SF_ERR_PARSE_ERROR` * It encountered fatal error while parsing field value. */ int sf_parser_item(sf_parser *sfp, sf_value *dest); /** * @function * * `sf_parser_inner_list` reads the next inner list item. If this * function returns 0, it stores the item in |dest| if it is not NULL. * * Caller can optionally read parameters attached to the item by * calling `sf_parser_param`. * * Caller should keep calling this function until it returns negative * error code. If it returns :macro:`SF_ERR_EOF`, all values in this * inner list have been read, and caller can optionally read * parameters attached to this inner list by calling * `sf_parser_param`. Then caller can continue to read rest of the * values. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`SF_ERR_EOF` * All values in the inner list have read. * :macro:`SF_ERR_PARSE_ERROR` * It encountered fatal error while parsing field value. */ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); /** * @function * * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). * |src| should be the pointer to :member:`sf_value.vec` of type * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or * `sf_parser_param`, otherwise the behavior is undefined. * * :member:`dest->base ` must point to the buffer that * has sufficient space to store the unescaped string. * * If there is no escape character in |src|, |*src| is assigned to * |*dest|. This includes the case that :member:`src->len * ` == 0. * * This function sets the length of unescaped string to * :member:`dest->len `. */ void sf_unescape(sf_vec *dest, const sf_vec *src); /** * @function * * `sf_base64decode` decodes Base64 encoded string |src| and writes * the result into |dest|. |src| should be the pointer to * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` * produced by either `sf_parser_dict`, `sf_parser_list`, * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, * otherwise the behavior is undefined. * * :member:`dest->base ` must point to the buffer that * has sufficient space to store the decoded byte string. * * If :member:`src->len ` == 0, |*src| is assigned to * |*dest|. * * This function sets the length of decoded byte string to * :member:`dest->len `. */ void sf_base64decode(sf_vec *dest, const sf_vec *src); #ifdef __cplusplus } #endif #endif /* SFPARSE_H */