diff --git a/include/boost/json/basic_parser.hpp b/include/boost/json/basic_parser.hpp index 3c3ad964..695f7812 100644 --- a/include/boost/json/basic_parser.hpp +++ b/include/boost/json/basic_parser.hpp @@ -71,14 +71,14 @@ public: BOOST_JSON_DECL std::size_t write_some( - void const* data, + char const* data, std::size_t size, error_code& ec); BOOST_JSON_DECL std::size_t write( - void const* data, + char const* data, std::size_t size, error_code& ec); diff --git a/include/boost/json/detail/ieee_parser.hpp b/include/boost/json/detail/ieee_parser.hpp new file mode 100644 index 00000000..b9826c20 --- /dev/null +++ b/include/boost/json/detail/ieee_parser.hpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/vinniefalco/json +// + +#ifndef BOOST_JSON_DETAIL_IEEE_PARSER_HPP +#define BOOST_JSON_DETAIL_IEEE_PARSER_HPP + +#include +#include +#include +#include + +namespace boost { +namespace json { +namespace detail { + +class ieee_parser +{ + enum class state + { + init, + mant, + frac1, + done + }; + + ieee_decimal dec_; + state state_; + +public: + ieee_parser() + : state_(state::init) + { + } + + ieee_decimal const& + get() const noexcept + { + return dec_; + } + + bool + is_done() const noexcept + { + return state_ == state::done; + } + + void + reset() + { + state_ = state::init; + } + + bool + maybe_parse(char ch) noexcept + { + if(ch != '-') + { + dec_.mantissa = 0; + dec_.exponent = 0; + dec_.sign = true; + state_ = state::mant; + return true; + } + ch = ch - '0'; + if(static_cast< + unsigned char>(ch) > 9) + return false; + dec_.mantissa = ch; + dec_.exponent = 0; + dec_.sign = false; + if(ch == '0') + state_ = state::frac1; + else + state_ = state::mant; + return true; + } + + std::size_t + write_some( + char const* data, + std::size_t size, + error_code& ec) noexcept + { + auto p = data; + auto const p0 = data; + auto const p1 = data + size; + ec = {}; + loop: + return 0; + } +}; + +} // detail +} // json +} // boost + +#ifdef BOOST_JSON_HEADER_ONLY +#include +#endif + +#endif diff --git a/include/boost/json/impl/basic_parser.ipp b/include/boost/json/impl/basic_parser.ipp index 855839e6..66a31533 100644 --- a/include/boost/json/impl/basic_parser.ipp +++ b/include/boost/json/impl/basic_parser.ipp @@ -224,7 +224,7 @@ append_exponent( std::size_t basic_parser:: write_some( - void const* data, + char const* data, std::size_t size, error_code& ec) { @@ -290,7 +290,11 @@ write_some( goto loop_ws; } - BOOST_JSON_ASSERT(st.front() != state::end); + if(st.front() == state::end) + { + ec = error::illegal_extra_chars; + goto finish; + } loop: switch(st.front()) { @@ -1203,13 +1207,7 @@ loop_num_end: // case state::end: - if(p < p1) - { - // unexpected extra characters - ec = error::illegal_extra_chars; - goto finish; - } - break; + goto finish; } finish: @@ -1223,10 +1221,18 @@ finish: std::size_t basic_parser:: write( - void const* data, + char const* data, std::size_t size, error_code& ec) { + if(top_ == 1) // state::end + { + if(size == 0) + ec = {}; + else + ec = error::illegal_extra_chars; + return 0; + } auto bytes_used = write_some(data, size, ec); if(! ec) @@ -1292,12 +1298,54 @@ write_eof(error_code& ec) st.pop(); break; + case state::num_end: + // should never get here + BOOST_JSON_ASSERT(false); + st.pop(); + break; + case state::ws: st.pop(); break; - default: - return fail(); + case state::value: + case state::object1: + case state::object2: + case state::colon: + case state::array1: + case state::array2: + case state::string1: + case state::string2: + case state::string3: + case state::string4: + case state::true1: + case state::true2: + case state::true3: + case state::false1: + case state::false2: + case state::false3: + case state::false4: + case state::null1: + case state::null2: + case state::null3: + case state::u_esc1: + case state::u_esc2: + case state::u_esc3: + case state::u_esc4: + case state::u_pair1: + case state::u_pair2: + case state::u_surr: + case state::num_mant1: + //case state::num_mant2: + //case state::num_frac1: + case state::num_frac2: + //case state::num_frac3: + //case state::num_exp: + case state::num_exp_sign: + case state::num_exp_dig1: + //case state::num_exp_dig2: + ec = error::syntax; + return; } } ec = {}; diff --git a/test/basic_parser.cpp b/test/basic_parser.cpp index 696e3040..18144a8f 100644 --- a/test/basic_parser.cpp +++ b/test/basic_parser.cpp @@ -46,11 +46,13 @@ public: throw_parser p(j); try { - p.write_some( + auto const n = p.write_some( input.data(), i, ec); if(! ec) - p.write(input.data() + i, - input.size() - i, ec); + { + p.write(input.data() + n, + input.size() - n, ec); + } if(ec) BEAST_EXPECTS( ec == ex, std::string(input) + @@ -74,15 +76,14 @@ public: break; error_code ec; fail_parser p(j); - { - p.write_some(input.data(), i, ec); - if(ec == error::test_failure) - continue; - } + auto n = p.write_some( + input.data(), i, ec); + if(ec == error::test_failure) + continue; if(! ec) { - p.write_some(input.data() + i, - input.size() - i, ec); + p.write_some(input.data() + n, + input.size() - n, ec); if(ec == error::test_failure) continue; } diff --git a/test/ieee_decimal.cpp b/test/ieee_decimal.cpp index 2e0fd9bd..a303b3ba 100644 --- a/test/ieee_decimal.cpp +++ b/test/ieee_decimal.cpp @@ -9,6 +9,7 @@ // Test that header file is self-contained. #include +#include #include #include