diff --git a/.github/workflows/build-and-test-rh.yml b/.github/workflows/build-and-test-rh.yml index c30fc19..65f88a9 100644 --- a/.github/workflows/build-and-test-rh.yml +++ b/.github/workflows/build-and-test-rh.yml @@ -87,6 +87,15 @@ jobs: run: sudo yum -y install findutils - name: Checkout shell test framework + if: matrix.image != 'centos:7' + uses: actions/checkout@v4 + with: + repository: kward/shunit2 + path: ${{github.workspace}}/tests/shunit2 + fetch-depth: 1 + + - name: Checkout shell test framework centos7 + if: matrix.image == 'centos:7' uses: actions/checkout@v3 with: repository: kward/shunit2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ac363c..d65b30e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,6 @@ if (BUILD_SHARED_LIBS AND MSVC) message(FATAL_ERROR "Building sexp shared library with MSVC is not supported") endif(BUILD_SHARED_LIBS AND MSVC) - message(STATUS "Building ${TYPE} library") if (WITH_SANITIZERS) @@ -107,7 +106,6 @@ if(NOT MSVC) -Wno-unused-parameter -Wno-missing-field-initializers ) - endif(NOT MSVC) add_library(sexpp ${TYPE} @@ -132,7 +130,10 @@ target_include_directories(sexpp PUBLIC if (BUILD_SHARED_LIBS) target_compile_definitions(sexpp PUBLIC BUILD_SHARED_LIBS) - set_target_properties(sexpp PROPERTIES CXX_VISIBILITY_PRESET "hidden") + set_target_properties(sexpp PROPERTIES + CXX_VISIBILITY_PRESET "hidden" + VISIBILITY_INLINES_HIDDEN true + ) endif (BUILD_SHARED_LIBS) set_target_properties(sexpp PROPERTIES diff --git a/include/sexpp/sexp.h b/include/sexpp/sexp.h index bb6ae4e..7e67d93 100644 --- a/include/sexpp/sexp.h +++ b/include/sexpp/sexp.h @@ -101,25 +101,25 @@ class sexp_input_stream_t; typedef uint8_t octet_t; -class SEXP_PUBLIC_SYMBOL sexp_simple_string_t : public std::basic_string, +class SEXP_PUBLIC_SYMBOL sexp_simple_string_t : public std::vector, private sexp_char_defs_t { public: sexp_simple_string_t(void) = default; - sexp_simple_string_t(const octet_t *dt) : std::basic_string{dt} {} - sexp_simple_string_t(const octet_t *bt, size_t ln) : std::basic_string{bt, ln} {} + sexp_simple_string_t(const octet_t *dt) : std::vector() { for (; *dt; ++dt) push_back(*dt); } + sexp_simple_string_t(const octet_t *bt, size_t ln) : std::vector(ln) { for (size_t s = 0; s < ln; ++bt, ++s ) push_back(*bt); } sexp_simple_string_t &append(int c) { - (*this) += (octet_t)(c & 0xFF); + push_back((octet_t)(c & 0xFF)); return *this; } // Returns length for printing simple string as a token - size_t advanced_length_token(void) const { return length(); } + size_t advanced_length_token(void) const { return size(); } // Returns length for printing simple string as a base64 string - size_t advanced_length_base64(void) const { return (2 + 4 * ((length() + 2) / 3)); } + size_t advanced_length_base64(void) const { return (2 + 4 * ((size() + 2) / 3)); } // Returns length for printing simple string ss in quoted-string mode - size_t advanced_length_quoted(void) const { return (1 + length() + 1); } + size_t advanced_length_quoted(void) const { return (1 + size() + 1); } // Returns length for printing simple string ss in hexadecimal mode - size_t advanced_length_hexadecimal(void) const { return (1 + 2 * length() + 1); } + size_t advanced_length_hexadecimal(void) const { return (1 + 2 * size() + 1); } size_t advanced_length(sexp_output_stream_t *os) const; sexp_output_stream_t *print_canonical_verbatim(sexp_output_stream_t *os) const; @@ -134,19 +134,15 @@ class SEXP_PUBLIC_SYMBOL sexp_simple_string_t : public std::basic_string::max() : - (unsigned) atoi(reinterpret_cast(c_str())); - } + uint32_t as_unsigned() const noexcept; }; inline bool operator==(const sexp_simple_string_t *left, const std::string &right) noexcept @@ -193,7 +189,7 @@ class SEXP_PUBLIC_SYMBOL sexp_object_t { } virtual bool operator==(const char *right) const noexcept { return false; } virtual bool operator!=(const char *right) const noexcept { return true; } - virtual unsigned as_unsigned() const noexcept + virtual uint32_t as_unsigned() const noexcept { return std::numeric_limits::max(); } @@ -250,17 +246,19 @@ class SEXP_PUBLIC_SYMBOL sexp_string_t : public sexp_object_t { virtual bool operator!=(const char *right) const noexcept { return data_string != right; } void parse(sexp_input_stream_t *sis); - virtual unsigned as_unsigned() const noexcept { return data_string.as_unsigned(); } + virtual uint32_t as_unsigned() const noexcept { return data_string.as_unsigned(); } }; inline bool operator==(const sexp_string_t *left, const std::string &right) noexcept { - return *left == right.c_str(); + return left->get_string().size() == right.length() && + memcmp(left->get_string().data(), right.c_str(), left->get_string().size()) == 0; } inline bool operator!=(const sexp_string_t *left, const std::string &right) noexcept { - return *left != right.c_str(); + return left->get_string().size() != right.length() || + memcmp(left->get_string().data(), right.c_str(), left->get_string().size()) != 0; } /* diff --git a/src/sexp-input.cpp b/src/sexp-input.cpp index cb21686..3538497 100644 --- a/src/sexp-input.cpp +++ b/src/sexp-input.cpp @@ -234,9 +234,9 @@ void sexp_input_stream_t::scan_verbatim_string(sexp_simple_string_t &ss, uint32_ void sexp_input_stream_t::scan_quoted_string(sexp_simple_string_t &ss, uint32_t length) { skip_char('"'); - while (ss.length() <= length) { + while (ss.size() <= length) { if (next_char == '\"') { - if (length == std::numeric_limits::max() || (ss.length() == length)) { + if (length == std::numeric_limits::max() || (ss.size() == length)) { skip_char('\"'); return; } else @@ -367,10 +367,10 @@ void sexp_input_stream_t::scan_hexadecimal_string(sexp_simple_string_t &ss, uint get_char(); } skip_char('#'); - if (ss.length() != length && length != std::numeric_limits::max()) + if (ss.size() != length && length != std::numeric_limits::max()) sexp_error(sexp_exception_t::warning, "Hex string has length %d different than declared length %d", - ss.length(), + ss.size(), length, count); } @@ -389,10 +389,10 @@ void sexp_input_stream_t::scan_base64_string(sexp_simple_string_t &ss, uint32_t get_char(); } skip_char('|'); - if (ss.length() != length && length != std::numeric_limits::max()) + if (ss.size() != length && length != std::numeric_limits::max()) sexp_error(sexp_exception_t::warning, "Base64 string has length %d different than declared length %d", - ss.length(), + ss.size(), length, count); } @@ -441,7 +441,7 @@ sexp_simple_string_t sexp_input_stream_t::scan_simple_string(void) } } - if (ss.length() == 0) + if (ss.size() == 0) sexp_error(sexp_exception_t::warning, "Simple string has zero length", 0, 0, count); return ss; } diff --git a/src/sexp-simple-string.cpp b/src/sexp-simple-string.cpp index 0e4c869..3029850 100644 --- a/src/sexp-simple-string.cpp +++ b/src/sexp-simple-string.cpp @@ -29,6 +29,27 @@ #include "sexpp/sexp.h" namespace sexp { + +/* + * sexp_simple_string_t::sexp_simple_string_t(const octet_t *dt) + */ +sexp_simple_string_t::sexp_simple_string_t(const octet_t *dt) : std::vector() +{ + for (; *dt; ++dt) + push_back(*dt); +} + +/* + * sexp_simple_string_t::sexp_simple_string_t(const octet_t *bt, size_t ln) + */ +sexp_simple_string_t::sexp_simple_string_t(const octet_t *bt, size_t ln) + : std::vector() +{ + reserve(ln); + for (size_t s = 0; s < ln; ++bt, ++s) + push_back(*bt); +} + /* * sexp_simple_string_t::print_canonical_verbatim(os) * Print out simple string on output stream os as verbatim string. @@ -36,11 +57,11 @@ namespace sexp { sexp_output_stream_t *sexp_simple_string_t::print_canonical_verbatim( sexp_output_stream_t *os) const { - const octet_t *c = c_str(); + const octet_t *c = data(); /* print out len: */ - os->print_decimal(length())->var_put_char(':'); + os->print_decimal(size())->var_put_char(':'); /* print characters in fragment */ - for (uint32_t i = 0; i < length(); i++) + for (uint32_t i = 0; i < size(); i++) os->var_put_char((int) *c++); return os; } @@ -55,7 +76,7 @@ size_t sexp_simple_string_t::advanced_length(sexp_output_stream_t *os) const return advanced_length_token(); else if (can_print_as_quoted_string()) return advanced_length_quoted(); - else if (length() <= 4 && os->get_byte_size() == 8) + else if (size() <= 4 && os->get_byte_size() == 8) return advanced_length_hexadecimal(); else if (os->get_byte_size() == 8) return advanced_length_base64(); @@ -63,6 +84,26 @@ size_t sexp_simple_string_t::advanced_length(sexp_output_stream_t *os) const return 0; /* an error condition */ } +/* + * sexp_simple_string_t::as_unsigned + * Converts simple string to unsigned integer. + * Returns std::numeric_limits::max() if simple string is empty + * Returns 0 if simple string contains non-digit characters + */ +uint32_t sexp_simple_string_t::as_unsigned() const noexcept +{ + if (empty()) + return std::numeric_limits::max(); + + uint32_t result = 0; + for (octet_t c : *this) { + if (!is_dec_digit(c)) + return 0; + result = result * 10 + (c - '0'); + } + return result; +} + /* * sexp_simple_string_t::print_token(os) * Prints out simple string ss as a token (assumes that this is OK). @@ -70,10 +111,10 @@ size_t sexp_simple_string_t::advanced_length(sexp_output_stream_t *os) const */ sexp_output_stream_t *sexp_simple_string_t::print_token(sexp_output_stream_t *os) const { - const octet_t *c = c_str(); - if (os->get_max_column() > 0 && os->get_column() > (os->get_max_column() - length())) + const octet_t *c = data(); + if (os->get_max_column() > 0 && os->get_column() > (os->get_max_column() - size())) os->new_line(sexp_output_stream_t::advanced); - for (uint32_t i = 0; i < length(); i++) + for (uint32_t i = 0; i < size(); i++) os->put_char((int) (*c++)); return os; } @@ -84,9 +125,9 @@ sexp_output_stream_t *sexp_simple_string_t::print_token(sexp_output_stream_t *os */ sexp_output_stream_t *sexp_simple_string_t::print_base64(sexp_output_stream_t *os) const { - const octet_t *c = c_str(); + const octet_t *c = data(); os->var_put_char('|')->change_output_byte_size(6, sexp_output_stream_t::advanced); - for (uint32_t i = 0; i < length(); i++) + for (uint32_t i = 0; i < size(); i++) os->var_put_char((int) (*c++)); return os->flush() ->change_output_byte_size(8, sexp_output_stream_t::advanced) @@ -99,9 +140,9 @@ sexp_output_stream_t *sexp_simple_string_t::print_base64(sexp_output_stream_t *o */ sexp_output_stream_t *sexp_simple_string_t::print_hexadecimal(sexp_output_stream_t *os) const { - const octet_t *c = c_str(); + const octet_t *c = data(); os->put_char('#')->change_output_byte_size(4, sexp_output_stream_t::advanced); - for (uint32_t i = 0; i < length(); i++) + for (uint32_t i = 0; i < size(); i++) os->var_put_char((int) (*c++)); return os->flush() ->change_output_byte_size(8, sexp_output_stream_t::advanced) @@ -117,9 +158,9 @@ sexp_output_stream_t *sexp_simple_string_t::print_hexadecimal(sexp_output_stream */ sexp_output_stream_t *sexp_simple_string_t::print_quoted(sexp_output_stream_t *os) const { - const octet_t *c = c_str(); + const octet_t *c = data(); os->put_char('\"'); - for (uint32_t i = 0; i < length(); i++) { + for (uint32_t i = 0; i < size(); i++) { if (os->get_max_column() > 0 && os->get_column() >= os->get_max_column() - 2) { os->put_char('\\')->put_char('\n'); os->reset_column(); @@ -139,7 +180,7 @@ sexp_output_stream_t *sexp_simple_string_t::print_advanced(sexp_output_stream_t print_token(os); else if (can_print_as_quoted_string()) print_quoted(os); - else if (length() <= 4 && os->get_byte_size() == 8) + else if (size() <= 4 && os->get_byte_size() == 8) print_hexadecimal(os); else if (os->get_byte_size() == 8) print_base64(os); @@ -159,8 +200,8 @@ sexp_output_stream_t *sexp_simple_string_t::print_advanced(sexp_output_stream_t */ bool sexp_simple_string_t::can_print_as_quoted_string(void) const { - const octet_t *c = c_str(); - for (uint32_t i = 0; i < length(); i++, c++) { + const octet_t *c = data(); + for (uint32_t i = 0; i < size(); i++, c++) { if (!is_token_char((int) (*c)) && *c != ' ') return false; } @@ -174,14 +215,14 @@ bool sexp_simple_string_t::can_print_as_quoted_string(void) const */ bool sexp_simple_string_t::can_print_as_token(const sexp_output_stream_t *os) const { - const octet_t *c = c_str(); - if (length() <= 0) + const octet_t *c = data(); + if (size() <= 0) return false; if (is_dec_digit((int) *c)) return false; - if (os->get_max_column() > 0 && os->get_column() + length() >= os->get_max_column()) + if (os->get_max_column() > 0 && os->get_column() + size() >= os->get_max_column()) return false; - for (uint32_t i = 0; i < length(); i++) { + for (uint32_t i = 0; i < size(); i++) { if (!is_token_char((int) (*c++))) return false; } diff --git a/tests/src/primitives-tests.cpp b/tests/src/primitives-tests.cpp index 0689d27..64b4b4f 100644 --- a/tests/src/primitives-tests.cpp +++ b/tests/src/primitives-tests.cpp @@ -201,7 +201,8 @@ TEST_F(PrimitivesTests, at4rnp) } const sexp_string_t *sstr = lst.sexp_string_at(0); - EXPECT_STREQ(reinterpret_cast(sstr->get_string().c_str()), "rnp_block"); + int result = memcmp(sstr->get_string().data(), "rnp_block", sstr->get_string().size()); + EXPECT_EQ(result, 0); } TEST_F(PrimitivesTests, eq4rnp) @@ -280,6 +281,15 @@ TEST_F(PrimitivesTests, u4rnp) EXPECT_EQ(lst.sexp_string_at(1)->as_unsigned(), 54321); } +TEST_F(PrimitivesTests, asUnsigned) +{ + sexp_simple_string_t sss1(reinterpret_cast("")); + EXPECT_EQ(sss1.as_unsigned(), std::numeric_limits::max()); + + sexp_simple_string_t sss2(reinterpret_cast("123A456")); + EXPECT_EQ(sss2.as_unsigned(), 0); +} + TEST_F(PrimitivesTests, proInheritance) { sexp_list_t lst; @@ -391,4 +401,15 @@ TEST_F(PrimitivesTests, EnsureHexTest) EXPECT_EQ(oss.str(), "(#610963#)"); } +TEST_F(PrimitivesTests, SimpleStringConstructors) +{ + const char *tss = "test simple string"; + + sexp_simple_string_t sss1(reinterpret_cast(tss)); + EXPECT_TRUE(sss1 == tss); + + sexp_simple_string_t sss2(reinterpret_cast(tss), 4); + EXPECT_TRUE(sss2 == "test"); +} + } // namespace diff --git a/version.txt b/version.txt index 1e9b46b..ac39a10 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.8.7 +0.9.0