Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ jobs:
build:
strategy:
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14, macos-15]
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-26, macos-15]
compiler: [gcc, clang]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Linux setup
Expand Down Expand Up @@ -93,7 +93,7 @@ jobs:
HOST: ${{ matrix.host }}

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Prepare for i386
Expand Down
34 changes: 34 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.15)
project(sfparse C)

option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(SFPARSE_ENABLE_INSTALL "Enable install" OFF)

include(GNUInstallDirs)

add_library(sfparse sfparse.c sfparse.h)
add_library(sfparse::sfparse ALIAS sfparse)

set(DEFINITIONS)
list(APPEND DEFINITIONS SFPARSE_BUILDING)
if(NOT BUILD_SHARED_LIBS)
list(APPEND DEFINITIONS SFPARSE_STATIC)
endif()
target_compile_definitions(sfparse PRIVATE ${DEFINITIONS})
target_include_directories(sfparse PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)

if(SFPARSE_ENABLE_INSTALL)
install(
FILES "${CMAKE_CURRENT_LIST_DIR}/sfparse.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/sfparse"
)
install(TARGETS sfparse EXPORT sfparse)
install(
EXPORT sfparse
NAMESPACE sfparse::
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/sfparse"
)
endif()
73 changes: 37 additions & 36 deletions sfparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@
# include <immintrin.h>
#endif /* __AVX2__ */

#define SFPARSE_STATE_DICT 0x08u
#define SFPARSE_STATE_LIST 0x10u
#define SFPARSE_STATE_ITEM 0x18u
#define SFPARSE_STATE_DICT 0x08U
#define SFPARSE_STATE_LIST 0x10U
#define SFPARSE_STATE_ITEM 0x18U

#define SFPARSE_STATE_INNER_LIST 0x04u
#define SFPARSE_STATE_INNER_LIST 0x04U

#define SFPARSE_STATE_BEFORE 0x00u
#define SFPARSE_STATE_BEFORE_PARAMS 0x01u
#define SFPARSE_STATE_PARAMS 0x02u
#define SFPARSE_STATE_AFTER 0x03u
#define SFPARSE_STATE_BEFORE 0x00U
#define SFPARSE_STATE_BEFORE_PARAMS 0x01U
#define SFPARSE_STATE_PARAMS 0x02U
#define SFPARSE_STATE_AFTER 0x03U

#define SFPARSE_STATE_OP_MASK 0x03u
#define SFPARSE_STATE_OP_MASK 0x03U

#define SFPARSE_SET_STATE_AFTER(NAME) \
(SFPARSE_STATE_##NAME | SFPARSE_STATE_AFTER)
Expand All @@ -69,7 +69,7 @@
#define SFPARSE_STATE_ITEM_INNER_LIST_BEFORE \
SFPARSE_SET_STATE_INNER_LIST_BEFORE(ITEM)

#define SFPARSE_STATE_INITIAL 0x00u
#define SFPARSE_STATE_INITIAL 0x00U

#define LCALPHAS \
['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, \
Expand Down Expand Up @@ -200,7 +200,7 @@ static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) {

#ifdef __AVX2__
if (sfp->end - sfp->pos >= 32) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);

sfp->pos = find_char_key(sfp->pos, last);
if (sfp->pos != last) {
Expand Down Expand Up @@ -349,7 +349,7 @@ static const uint8_t *find_char_string(const uint8_t *first,
const uint8_t *last) {
const __m256i bs = _mm256_set1_epi8('\\');
const __m256i dq = _mm256_set1_epi8('"');
const __m256i del = _mm256_set1_epi8(0x7f);
const __m256i del = _mm256_set1_epi8(0x7F);
const __m256i sp = _mm256_set1_epi8(' ');
__m256i s, x;
uint32_t m;
Expand Down Expand Up @@ -394,7 +394,7 @@ static int parser_string(sfparse_parser *sfp, sfparse_value *dest) {

#ifdef __AVX2__
for (; sfp->end - sfp->pos >= 32; ++sfp->pos) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);

sfp->pos = find_char_string(sfp->pos, last);
if (sfp->pos == last) {
Expand Down Expand Up @@ -541,7 +541,7 @@ static int parser_token(sfparse_parser *sfp, sfparse_value *dest) {

#ifdef __AVX2__
if (sfp->end - sfp->pos >= 32) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);

sfp->pos = find_char_token(sfp->pos, last);
if (sfp->pos != last) {
Expand Down Expand Up @@ -622,7 +622,7 @@ static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) {

#ifdef __AVX2__
if (sfp->end - sfp->pos >= 32) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);
sfp->pos = find_char_byteseq(sfp->pos, last);
}
#endif /* __AVX2__ */
Expand Down Expand Up @@ -856,34 +856,35 @@ static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) {
case 0:
return SFPARSE_ERR_PARSE;
case 1:
if (utf8state != UTF8_ACCEPT) {
return SFPARSE_ERR_PARSE;
}

++sfp->pos;

break;
case 2:
++sfp->pos;
for (;;) {
++sfp->pos;

if (sfp->pos + 2 > sfp->end) {
return SFPARSE_ERR_PARSE;
}
if (sfp->pos + 2 > sfp->end || pctdecode(&c, &sfp->pos) != 0) {
return SFPARSE_ERR_PARSE;
}

if (pctdecode(&c, &sfp->pos) != 0) {
return SFPARSE_ERR_PARSE;
}
utf8_decode(&utf8state, c);
if (utf8state == UTF8_ACCEPT) {
if (sfp->pos != sfp->end && *sfp->pos == '%') {
continue;
}

utf8_decode(&utf8state, c);
if (utf8state == UTF8_REJECT) {
return SFPARSE_ERR_PARSE;
break;
}

if (utf8state == UTF8_REJECT || sfp->pos + 1 > sfp->end ||
*sfp->pos != '%') {
return SFPARSE_ERR_PARSE;
}
}

break;
case 3:
if (utf8state != UTF8_ACCEPT) {
return SFPARSE_ERR_PARSE;
}
assert(utf8state == UTF8_ACCEPT);

if (dest) {
dest->type = SFPARSE_TYPE_DISPSTRING;
Expand Down Expand Up @@ -1428,8 +1429,8 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) {
}

*o++ = (uint8_t)(n >> 16);
*o++ = (n >> 8) & 0xffu;
*o++ = n & 0xffu;
*o++ = (n >> 8) & 0xFFU;
*o++ = n & 0xFFU;
}

switch (left) {
Expand Down Expand Up @@ -1466,8 +1467,8 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) {
n = (uint32_t)(index_tbl[*p++] << 10);
n += (uint32_t)(index_tbl[*p++] << 4);
n += (uint32_t)(index_tbl[*p++] >> 2);
*o++ = (n >> 8) & 0xffu;
*o++ = n & 0xffu;
*o++ = (n >> 8) & 0xFFU;
*o++ = n & 0xFFU;

break;
}
Expand Down
50 changes: 36 additions & 14 deletions sfparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@
# define WIN32
#endif /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */

#if defined(_WIN32)
# if defined(SFPARSE_STATIC)
# define SFPARSE_API
# elif defined(SFPARSE_BUILDING)
# define SFPARSE_API __declspec(dllexport)
# else
# define SFPARSE_API __declspec(dllimport)
# endif
#elif defined(__GNUC__) || defined(__clang__)
# if defined(SFPARSE_STATIC)
# define SFPARSE_API
# elif defined(SFPARSE_BUILDING)
# define SFPARSE_API __attribute__((visibility("default")))
# else
# define SFPARSE_API
# endif
#else
# define SFPARSE_API
#endif

#ifdef __cplusplus
extern "C" {
#endif /* defined(__cplusplus) */
Expand Down Expand Up @@ -130,15 +150,15 @@ typedef struct sfparse_vec {
*
* :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set.
*/
#define SFPARSE_VALUE_FLAG_NONE 0x0u
#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
#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1U

/**
* @struct
Expand Down Expand Up @@ -247,8 +267,8 @@ typedef struct sfparse_parser {
* `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);
SFPARSE_API void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data,
size_t datalen);

/**
* @function
Expand All @@ -266,8 +286,8 @@ void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data,
* 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);
SFPARSE_API int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key,
sfparse_value *dest_value);

/**
* @function
Expand All @@ -294,8 +314,8 @@ int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key,
* :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);
SFPARSE_API int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key,
sfparse_value *dest_value);

/**
* @function
Expand All @@ -318,7 +338,7 @@ int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key,
* :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value.
*/
int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest);
SFPARSE_API int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest);

/**
* @function
Expand All @@ -345,7 +365,7 @@ int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest);
* :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value.
*/
int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest);
SFPARSE_API int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest);

/**
* @function
Expand All @@ -372,7 +392,8 @@ int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest);
* :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value.
*/
int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest);
SFPARSE_API int sfparse_parser_inner_list(sfparse_parser *sfp,
sfparse_value *dest);

/**
* @function
Expand All @@ -393,7 +414,7 @@ int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest);
* This function sets the length of unescaped string to
* :member:`dest->len <sfparse_vec.len>`.
*/
void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src);
SFPARSE_API void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src);

/**
* @function
Expand All @@ -412,7 +433,8 @@ void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src);
* This function sets the length of decoded byte string to
* :member:`dest->len <sfparse_vec.len>`.
*/
void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src);
SFPARSE_API void sfparse_base64decode(sfparse_vec *dest,
const sfparse_vec *src);

/**
* @function
Expand All @@ -433,7 +455,7 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src);
* This function sets the length of decoded byte string to
* :member:`dest->len <sfparse_vec.len>`.
*/
void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src);
SFPARSE_API void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src);

#ifdef __cplusplus
}
Expand Down
4 changes: 2 additions & 2 deletions sfparse_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -3848,8 +3848,8 @@ void test_sfparse_parser_string_generated(void) {

rv = sfparse_parser_item(&sfp, &val);

if (i == 0x20 || i == 0x21 || (0x23 <= i && i <= 0x5b) ||
(0x5d <= i && i <= 0x7e) || i == 0x22) {
if (i == 0x20 || i == 0x21 || (0x23 <= i && i <= 0x5B) ||
(0x5D <= i && i <= 0x7E) || i == 0x22) {
assert_int(0, ==, rv);

rv = sfparse_parser_item(&sfp, NULL);
Expand Down