diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1542d5a..422e500 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 @@ -93,7 +93,7 @@ jobs: HOST: ${{ matrix.host }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: submodules: recursive - name: Prepare for i386 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ce3f7d9 --- /dev/null +++ b/CMakeLists.txt @@ -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 + "$" + "$" +) + +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() diff --git a/sfparse.c b/sfparse.c index 77ad937..c312c04 100644 --- a/sfparse.c +++ b/sfparse.c @@ -34,18 +34,18 @@ # include #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) @@ -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, \ @@ -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) { @@ -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; @@ -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) { @@ -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) { @@ -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__ */ @@ -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; @@ -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) { @@ -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; } diff --git a/sfparse.h b/sfparse.h index 9341221..31a02c0 100644 --- a/sfparse.h +++ b/sfparse.h @@ -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) */ @@ -130,7 +150,7 @@ 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 @@ -138,7 +158,7 @@ typedef struct sfparse_vec { * :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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 `. */ -void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src); +SFPARSE_API void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src); /** * @function @@ -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 `. */ -void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src); +SFPARSE_API void sfparse_base64decode(sfparse_vec *dest, + const sfparse_vec *src); /** * @function @@ -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 `. */ -void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); +SFPARSE_API void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); #ifdef __cplusplus } diff --git a/sfparse_test.c b/sfparse_test.c index 5c1952a..49780ab 100644 --- a/sfparse_test.c +++ b/sfparse_test.c @@ -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);