/* * 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 /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */ #ifdef __cplusplus extern "C" { #endif /* defined(__cplusplus) */ #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:`sfparse_type` defines value type. */ typedef enum sfparse_type { /** * :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type. */ SFPARSE_TYPE_BOOLEAN, /** * :enum:`SFPARSE_TYPE_INTEGER` indicates integer type. */ SFPARSE_TYPE_INTEGER, /** * :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type. */ SFPARSE_TYPE_DECIMAL, /** * :enum:`SFPARSE_TYPE_STRING` indicates string type. */ SFPARSE_TYPE_STRING, /** * :enum:`SFPARSE_TYPE_TOKEN` indicates token type. */ SFPARSE_TYPE_TOKEN, /** * :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type. */ SFPARSE_TYPE_BYTESEQ, /** * :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type. */ SFPARSE_TYPE_INNER_LIST, /** * :enum:`SFPARSE_TYPE_DATE` indicates date type. */ SFPARSE_TYPE_DATE, /** * :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type. */ SFPARSE_TYPE_DISPSTRING } sfparse_type; /** * @macro * * :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has * occurred, and it is not possible to continue the processing. */ #define SFPARSE_ERR_PARSE -1 /** * @macro * * :macro:`SFPARSE_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 SFPARSE_ERR_EOF -2 /** * @struct * * :type:`sfparse_vec` stores sequence of bytes. */ typedef struct sfparse_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; } sfparse_vec; /** * @macro * * :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set. */ #define SFPARSE_VALUE_FLAG_NONE 0x0u /** * @macro * * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string * contains escaped character(s). */ #define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u /** * @struct * * :type:`sfparse_decimal` contains decimal value. */ typedef struct sfparse_decimal { /** * :member:`numer` contains numerator of the decimal value. */ int64_t numer; /** * :member:`denom` contains denominator of the decimal value. */ int64_t denom; } sfparse_decimal; /** * @struct * * :type:`sfparse_value` stores a Structured Field item. For Inner * List, only type is set to * :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the * items contained in an inner list, call `sfparse_parser_inner_list`. */ typedef struct sfparse_value { /** * :member:`type` is the type of the value contained in this * particular object. */ sfparse_type type; /** * :member:`flags` is bitwise OR of one or more of * :macro:`SFPARSE_VALUE_FLAG_* `. */ uint32_t flags; /** * @anonunion_start * * @sfparse_value_value */ union { /** * :member:`boolean` contains boolean value if :member:`type` == * :enum:`sfparse_type.SFPARSE_TYPE_BOOLEAN`. 1 indicates true, * and 0 indicates false. */ int boolean; /** * :member:`integer` contains integer value if :member:`type` is * either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or * :enum:`sfparse_type.SFPARSE_TYPE_DATE`. */ int64_t integer; /** * :member:`decimal` contains decimal value if :member:`type` == * :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`. */ sfparse_decimal decimal; /** * :member:`vec` contains sequence of bytes if :member:`type` is * either :enum:`sfparse_type.SFPARSE_TYPE_STRING`, * :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`, * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`. * * For :enum:`sfparse_type.SFPARSE_TYPE_STRING`, this field * contains one or more escaped characters if :member:`flags` has * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape * the string, use `sfparse_unescape`. * * For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field * contains base64 encoded string. To decode this byte string, * use `sfparse_base64decode`. * * For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field * may contain percent-encoded UTF-8 byte sequences. To decode * it, use `sfparse_pctdecode`. * * If :member:`vec.len ` == 0, :member:`vec.base * ` is guaranteed to be NULL. */ sfparse_vec vec; /** * @anonunion_end */ }; } sfparse_value; /** * @struct * * :type:`sfparse_parser` is the Structured Field Values parser. Use * `sfparse_parser_init` to initialize it. */ typedef struct sfparse_parser { /* all fields are private */ const uint8_t *pos; const uint8_t *end; uint32_t state; } sfparse_parser; /** * @function * * `sfparse_parser_init` initializes |sfp| with the given data encoded * in Structured Field Values pointed by |data| of length |datalen|. */ void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, size_t datalen); /** * @function * * `sfparse_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:`SFPARSE_ERR_EOF`, all parameters * have read, and caller can continue to read rest of the values. If * it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error * while parsing field value. */ int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, sfparse_value *dest_value); /** * @function * * `sfparse_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 `sfparse_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:`SFPARSE_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:`SFPARSE_ERR_EOF` * All values in the dictionary have read. * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, sfparse_value *dest_value); /** * @function * * `sfparse_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 `sfparse_parser_param`. * * Caller should keep calling this function until it returns negative * error code. If it returns :macro:`SFPARSE_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:`SFPARSE_ERR_EOF` * All values in the list have read. * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest); /** * @function * * `sfparse_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 `sfparse_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:`SFPARSE_ERR_EOF`, all data have been processed * successfully. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`SFPARSE_ERR_EOF` * There is nothing left to read. * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest); /** * @function * * `sfparse_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 `sfparse_parser_param`. * * Caller should keep calling this function until it returns negative * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in * this inner list have been read, and caller can optionally read * parameters attached to this inner list by calling * `sfparse_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:`SFPARSE_ERR_EOF` * All values in the inner list have read. * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest); /** * @function * * `sfparse_unescape` copies |src| to |dest| by removing escapes * (``\``). |src| should be the pointer to * :member:`sfparse_value.vec` of type * :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either * `sfparse_parser_dict`, `sfparse_parser_list`, * `sfparse_parser_inner_list`, `sfparse_parser_item`, or * `sfparse_parser_param`, otherwise the behavior is undefined. * * :member:`dest->base ` must point to the buffer * that has sufficient space to store the unescaped string. The * memory areas pointed by :member:`dest->base ` and * :member:`src->base ` must not overlap. * * This function sets the length of unescaped string to * :member:`dest->len `. */ void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src); /** * @function * * `sfparse_base64decode` decodes Base64 encoded string |src| and * writes the result into |dest|. |src| should be the pointer to * :member:`sfparse_value.vec` of type * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either * `sfparse_parser_dict`, `sfparse_parser_list`, * `sfparse_parser_inner_list`, `sfparse_parser_item`, or * `sfparse_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. * * This function sets the length of decoded byte string to * :member:`dest->len `. */ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src); /** * @function * * `sfparse_pctdecode` decodes percent-encoded string |src| and writes * the result into |dest|. |src| should be the pointer to * :member:`sfparse_value.vec` of type * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either * `sfparse_parser_dict`, `sfparse_parser_list`, * `sfparse_parser_inner_list`, `sfparse_parser_item`, or * `sfparse_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. The * memory areas pointed by :member:`dest->base ` and * :member:`src->base ` must not overlap. * * This function sets the length of decoded byte string to * :member:`dest->len `. */ void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); #ifdef __cplusplus } #endif /* defined(__cplusplus) */ #endif /* !defined(SFPARSE_H) */