diff --git a/src/json.hpp b/src/json.hpp index 160fa4eb..516f2bbb 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1410,48 +1410,51 @@ using input_adapter_t = std::shared_ptr; class input_stream_adapter : public input_adapter_protocol { public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not maintain ifstream flags + is.clear(); + } explicit input_stream_adapter(std::istream& i) : is(i) { - // Ignore Byte Order Mark at start of input - int c; - if (( c = get_character() ) == 0xEF ) - { - if (( c = get_character() ) == 0xBB ) - { - if (( c = get_character() ) == 0xBF ) - { - return; // Ignore BOM - } - else if ( c != std::char_traits::eof() ) - { - is.unget(); - } - is.putback( '\xBB' ); - } - else if ( c != std::char_traits::eof() ) - { - is.unget(); - } - is.putback( '\xEF' ); - } - else if ( c != std::char_traits::eof() ) - { - is.unget(); // Not BOM. Process as usual. - } + // Ignore Byte Order Mark at start of input + int c; + if (( c = get_character() ) == 0xEF ) + { + if (( c = get_character() ) == 0xBB ) + { + if (( c = get_character() ) == 0xBF ) + { + return; // Ignore BOM + } + else if ( c != std::char_traits::eof() ) + { + is.unget(); + } + is.putback( '\xBB' ); + } + else if ( c != std::char_traits::eof() ) + { + is.unget(); + } + is.putback( '\xEF' ); + } + else if ( c != std::char_traits::eof() ) + { + is.unget(); // Not BOM. Process as usual. + } } - ~input_stream_adapter() override {} - int get_character() override { - int c = is.get(); - return c == std::char_traits::eof() ? c : ( c & 0xFF ); + int c = is.rdbuf()->sbumpc(); // Avoided for performance: int c = is.get(); + return c == std::char_traits::eof() ? c : ( c & 0xFF ); } void unget_character() override { - is.unget(); + is.rdbuf()->sungetc(); // Avoided for performance: is.unget(); } private: @@ -1489,10 +1492,10 @@ class input_buffer_adapter : public input_adapter_protocol void unget_character() noexcept override { - if (JSON_LIKELY(cursor > 0)) - { - --cursor; - } + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } } private: @@ -2571,7 +2574,7 @@ scan_number_any2: scan_number_done: // unget the character after the number (we only read it to know that // we are done scanning a number) - unget(); + unget(); // terminate token add('\0'); @@ -2652,29 +2655,31 @@ scan_number_done: void reset() noexcept { yylen = 0; - start_pos = chars_read - 1; - token_string = static_cast( current ); + token_string.clear(); + token_string.push_back(static_cast(current)); } /// get a character from the input int get() { ++chars_read; - - int c = current = ia->get_character(); - token_string += static_cast( c ); - return c; + int c = current = ia->get_character(); + token_string.push_back(static_cast(c)); + return c; } /// unget current character (return it again on next get) void unget() { --chars_read; - - if (token_string.size() > 0) - token_string.resize( token_string.size() - 1 ); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + } + if (! token_string.empty()) + token_string.pop_back(); } - + /// add a character to yytext void add(int c) { @@ -2736,10 +2741,12 @@ scan_number_done: std::string result; for (auto c : token_string) { - if ( c == std::char_traits::eof() ) { - continue; - } - else if ('\x00' <= c and c <= '\x1f') + if (c == '\0' or c == std::char_traits::eof()) + { + // ignore EOF + continue; + } + else if ('\x00' <= c and c <= '\x1f') { // escape control characters std::stringstream ss; @@ -2840,10 +2847,8 @@ scan_number_done: /// the number of characters read std::size_t chars_read = 0; - /// the start position of the current token - std::size_t start_pos = 0; /// raw input token string (for error messages) - std::string token_string = ""; + std::vector token_string = std::vector(); /// buffer for variable-length tokens (numbers, strings) std::vector yytext = std::vector(1024, '\0');