From ff339250cbaf0ad89344ac57c5a0c760f4ecf8a2 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Sun, 10 Nov 2019 14:41:24 +0100 Subject: [PATCH 1/2] Resolve core #1116 by removing fc::[io]fstream --- CMakeLists.txt | 1 - include/fc/io/fstream.hpp | 57 ---------- include/fc/io/json.hpp | 18 +++- include/fc/io/json_relaxed.hpp | 85 +++++++-------- src/crypto/aes.cpp | 11 +- src/filesystem.cpp | 4 +- src/io/fstream.cpp | 117 --------------------- src/io/json.cpp | 185 +++++++++++++++++---------------- src/log/file_appender.cpp | 14 ++- tests/io/json_tests.cpp | 13 +-- tests/io/stream_tests.cpp | 101 ------------------ tests/logging_tests.cpp | 21 ++-- 12 files changed, 191 insertions(+), 436 deletions(-) delete mode 100644 include/fc/io/fstream.hpp delete mode 100644 src/io/fstream.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 092d74d78..0a297bfd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,7 +180,6 @@ set( fc_sources src/io/iostream.cpp src/io/datastream.cpp src/io/buffered_iostream.cpp - src/io/fstream.cpp src/io/sstream.cpp src/io/json.cpp src/io/varint.cpp diff --git a/include/fc/io/fstream.hpp b/include/fc/io/fstream.hpp deleted file mode 100644 index 7b5465e4a..000000000 --- a/include/fc/io/fstream.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace fc { - class path; - class ofstream : virtual public ostream { - public: - ofstream(); - ofstream( const fc::path& file, std::ios_base::openmode m = std::ios_base::out | std::ios_base::binary ); - ~ofstream(); - - void open( const fc::path& file, std::ios_base::openmode m = std::ios_base::out | std::ios_base::binary ); - size_t writesome( const char* buf, size_t len ); - size_t writesome(const std::shared_ptr& buffer, size_t len, size_t offset); - void put( char c ); - void close(); - void flush(); - - private: - class impl; - std::shared_ptr my; - }; - - class ifstream : virtual public istream { - public: - enum mode { in, binary }; - enum seekdir { beg, cur, end }; - - ifstream(); - ifstream( const fc::path& file, int m = binary); - ~ifstream(); - - void open( const fc::path& file, int m ); - size_t readsome( char* buf, size_t len ); - size_t readsome(const std::shared_ptr& buffer, size_t max, size_t offset); - ifstream& read( char* buf, size_t len ); - ifstream& seekg( size_t p, seekdir d = beg ); - using istream::get; - void get( char& c ) { read( &c, 1 ); } - void close(); - bool eof()const; - private: - class impl; - std::shared_ptr my; - }; - - /** - * Grab the full contents of a file into a string object. - * NB reading a full file into memory is a poor choice - * if the file may be very large. - */ - void read_file_contents( const fc::path& filename, std::string& result ); - -} // namespace fc diff --git a/include/fc/io/json.hpp b/include/fc/io/json.hpp index 0f97c40df..24690be47 100644 --- a/include/fc/io/json.hpp +++ b/include/fc/io/json.hpp @@ -2,6 +2,8 @@ #include #include +#include + #define DEFAULT_MAX_RECURSION_DEPTH 200 namespace fc @@ -33,12 +35,18 @@ namespace fc legacy_generator = 1 }; - static ostream& to_stream( ostream& out, const std::string& ); - static ostream& to_stream( ostream& out, const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); - static ostream& to_stream( ostream& out, const variants& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); - static ostream& to_stream( ostream& out, const variant_object& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); + static std::ostream& to_stream( std::ostream& out, const std::string& ); + static std::ostream& to_stream( std::ostream& out, const variant& v, + output_formatting format = stringify_large_ints_and_doubles, + uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); + static std::ostream& to_stream( std::ostream& out, const variants& v, + output_formatting format = stringify_large_ints_and_doubles, + uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); + static std::ostream& to_stream( std::ostream& out, const variant_object& v, + output_formatting format = stringify_large_ints_and_doubles, + uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); - static variant from_stream( buffered_istream& in, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); + static variant from_stream( std::istream& in, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); static variant from_string( const string& utf8_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); static variants variants_from_string( const string& utf8_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); diff --git a/include/fc/io/json_relaxed.hpp b/include/fc/io/json_relaxed.hpp index 00893a342..bf3683abf 100644 --- a/include/fc/io/json_relaxed.hpp +++ b/include/fc/io/json_relaxed.hpp @@ -5,31 +5,21 @@ #include #include -#include -#include -#include -#include #include -//#include -#include -#include -#include -#include +#include namespace fc { namespace json_relaxed { - template - variant variant_from_stream( T& in, uint32_t max_depth ); + template + variant variant_from_stream( std::istream& in, uint32_t max_depth ); - template - std::string tokenFromStream( T& in ) + std::string tokenFromStream( std::istream& in ) { fc::stringstream token; try { - char c = in.peek(); - + char c; while( true ) { switch( c = in.peek() ) @@ -60,6 +50,8 @@ namespace fc { namespace json_relaxed token << c; in.get(); break; + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: return token.str(); } @@ -79,8 +71,8 @@ namespace fc { namespace json_relaxed ("token", token.str() ) ); } - template - std::string quoteStringFromStream( T& in ) + template + std::string quoteStringFromStream( std::istream& in ) { fc::stringstream token; try @@ -147,6 +139,7 @@ namespace fc { namespace json_relaxed ("token", token.str() ) ); else if( allow_escape && (c == '\\') ) token << parseEscape( in ); + else if( c == EOF && in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); else { in.get(); @@ -159,7 +152,6 @@ namespace fc { namespace json_relaxed while( true ) { char c = in.peek(); - if( c == q ) { in.get(); @@ -173,6 +165,7 @@ namespace fc { namespace json_relaxed else if( (c == '\r') | (c == '\n') ) FC_THROW_EXCEPTION( parse_error_exception, "unexpected EOL in string '${token}'", ("token", token.str() ) ); + else if( c == EOF && in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); else { in.get(); @@ -184,8 +177,8 @@ namespace fc { namespace json_relaxed ("token", token.str() ) ); } - template - std::string stringFromStream( T& in ) + template + std::string stringFromStream( std::istream& in ) { try { @@ -198,7 +191,7 @@ namespace fc { namespace json_relaxed FC_THROW_EXCEPTION( parse_error_exception, "expected: '\"' at beginning of string, got '\''" ); // falls through case '"': - return quoteStringFromStream( in ); + return quoteStringFromStream( in ); case 'r': if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "raw strings not supported in strict mode" ); @@ -211,7 +204,9 @@ namespace fc { namespace json_relaxed case '\'': if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "raw strings not supported in strict mode" ); - return quoteStringFromStream( in ); + return quoteStringFromStream( in ); + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "unquoted strings not supported in strict mode" ); @@ -569,23 +564,29 @@ namespace fc { namespace json_relaxed } } FC_CAPTURE_AND_RETHROW( (token) ) } - template - variant_object objectFromStream( T& in, uint32_t max_depth ) + template + variant_object objectFromStream( std::istream& in, uint32_t max_depth ) { - std::function get_key = []( T& in ){ return json_relaxed::stringFromStream( in ); }; - std::function get_value = [max_depth]( T& in ){ return json_relaxed::variant_from_stream( in, max_depth ); }; - return objectFromStreamBase( in, get_key, get_value ); + std::function get_key = []( std::istream& in ){ + return json_relaxed::stringFromStream( in ); + }; + std::function get_value = [max_depth]( std::istream& in ){ + return json_relaxed::variant_from_stream( in, max_depth ); + }; + return objectFromStreamBase( in, get_key, get_value ); } - template - variants arrayFromStream( T& in, uint32_t max_depth ) + template + variants arrayFromStream( std::istream& in, uint32_t max_depth ) { - std::function get_value = [max_depth]( T& in ){ return json_relaxed::variant_from_stream( in, max_depth ); }; - return arrayFromStreamBase( in, get_value ); + std::function get_value = [max_depth]( std::istream& in ){ + return json_relaxed::variant_from_stream( in, max_depth ); + }; + return arrayFromStreamBase( in, get_value ); } - template - variant numberFromStream( T& in ) + template + variant numberFromStream( std::istream& in ) { try { std::string token = tokenFromStream(in); variant result = json_relaxed::parseNumberOrStr( token ); @@ -594,8 +595,8 @@ namespace fc { namespace json_relaxed return result; } FC_CAPTURE_AND_RETHROW() } - template - variant wordFromStream( T& in ) + template + variant wordFromStream( std::istream& in ) { std::string token = tokenFromStream(in); @@ -625,8 +626,8 @@ namespace fc { namespace json_relaxed FC_THROW_EXCEPTION( parse_error_exception, "expected: null|true|false" ); } - template - variant variant_from_stream( T& in, uint32_t max_depth ) + template + variant variant_from_stream( std::istream& in, uint32_t max_depth ) { if( max_depth == 0 ) FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" ); @@ -635,11 +636,11 @@ namespace fc { namespace json_relaxed switch( c ) { case '"': - return json_relaxed::stringFromStream( in ); + return json_relaxed::stringFromStream( in ); case '{': - return json_relaxed::objectFromStream( in, max_depth - 1 ); + return json_relaxed::objectFromStream( in, max_depth - 1 ); case '[': - return json_relaxed::arrayFromStream( in, max_depth - 1 ); + return json_relaxed::arrayFromStream( in, max_depth - 1 ); case '-': case '+': case '.': @@ -653,7 +654,7 @@ namespace fc { namespace json_relaxed case '7': case '8': case '9': - return json_relaxed::numberFromStream( in ); + return json_relaxed::numberFromStream( in ); // null, true, false, or 'warning' / string case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': @@ -664,7 +665,7 @@ namespace fc { namespace json_relaxed case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case '/': - return json_relaxed::wordFromStream( in ); + return json_relaxed::wordFromStream( in ); case 0x04: // ^D end of transmission case EOF: FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp index 55464a7c9..e38e91a3e 100644 --- a/src/crypto/aes.cpp +++ b/src/crypto/aes.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include @@ -17,6 +15,9 @@ #endif #include +#include +#include + #if defined(_WIN32) # include #endif @@ -358,7 +359,8 @@ void aes_save( const fc::path& file, const fc::sha512& key, std::ve fc::raw::pack( check_enc, cipher ); auto check = check_enc.result(); - fc::ofstream out(file); + std::ofstream out( file.string(), std::ios_base::binary ); + FC_ASSERT( !out.fail() && !out.bad(), "Failed to open file '${f}'", ("f",file.string()) ); fc::raw::pack( out, check ); fc::raw::pack( out, cipher ); } FC_RETHROW_EXCEPTIONS( warn, "", ("file",file) ) } @@ -370,7 +372,8 @@ std::vector aes_load( const fc::path& file, const fc::sha512& key ) { try { FC_ASSERT( fc::exists( file ) ); - fc::ifstream in( file, fc::ifstream::binary ); + std::ifstream in( file.string(), std::ios_base::binary ); + FC_ASSERT( !in.fail() && !in.bad(), "Failed to open file '${f}'", ("f",file.string()) ); fc::sha512 check; std::vector cipher; diff --git a/src/filesystem.cpp b/src/filesystem.cpp index d6abc20a2..542030106 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include @@ -370,7 +369,8 @@ namespace fc { } if (create) { - fc::ofstream ofs(*_path, std::ios_base::out | std::ios_base::binary); + std::ofstream ofs( _path->string(), std::ios_base::binary); + FC_ASSERT( !ofs.fail() && !ofs.bad(), "Failed to open file '${f}'", ("f",_path->string()) ); ofs.close(); } } diff --git a/src/io/fstream.cpp b/src/io/fstream.cpp deleted file mode 100644 index 1e6fffeb4..000000000 --- a/src/io/fstream.cpp +++ /dev/null @@ -1,117 +0,0 @@ - -#include -#include - -#include -#include -#include -#include - -#include -#include - -using namespace std; - -namespace fc { - class ofstream::impl { - public: - boost::filesystem::ofstream ofs; - }; - class ifstream::impl { - public: - boost::filesystem::ifstream ifs; - }; - - ofstream::ofstream() - :my( new impl() ){} - - ofstream::ofstream( const fc::path& file, std::ios_base::openmode m ) - :my( new impl() ) { this->open( file, m ); } - ofstream::~ofstream(){} - - void ofstream::open( const fc::path& file, std::ios_base::openmode m ) { - const boost::filesystem::path& bfp = file; - my->ofs.open( bfp, std::ios_base::out | std::ios_base::binary | m ); - } - size_t ofstream::writesome( const char* buf, size_t len ) { - my->ofs.write(buf,len); - return len; - } - size_t ofstream::writesome(const std::shared_ptr& buffer, size_t len, size_t offset) - { - return writesome(buffer.get() + offset, len); - } - - void ofstream::put( char c ) { - my->ofs.put(c); - } - void ofstream::close() { - my->ofs.close(); - } - void ofstream::flush() { - my->ofs.flush(); - } - - ifstream::ifstream() - :my(new impl()){} - ifstream::ifstream( const fc::path& file, int m ) - :my(new impl()) - { - this->open( file, m ); - } - ifstream::~ifstream(){} - - void ifstream::open( const fc::path& file, int m ) { - const boost::filesystem::path& bfp = file; - my->ifs.open( bfp, std::ios::binary ); - } - - size_t ifstream::readsome( char* buf, size_t len ) { - auto s = size_t(my->ifs.readsome( buf, len )); - if( s <= 0 ) - { - read( buf, 1 ); - s = 1; - if (len > 1) - { - s += size_t(my->ifs.readsome( &buf[1], len - 1)); - } - } - return s; - } - size_t ifstream::readsome(const std::shared_ptr& buffer, size_t max, size_t offset) - { - return readsome(buffer.get() + offset, max); - } - - ifstream& ifstream::read( char* buf, size_t len ) { - if (eof()) - FC_THROW_EXCEPTION( eof_exception , ""); - my->ifs.read(buf,len); - if (my->ifs.gcount() < int64_t(len)) - FC_THROW_EXCEPTION( eof_exception , ""); - return *this; - } - ifstream& ifstream::seekg( size_t p, seekdir d ) { - switch( d ) { - case beg: my->ifs.seekg( p, std::ios_base::beg ); return *this; - case cur: my->ifs.seekg( p, std::ios_base::cur ); return *this; - case end: my->ifs.seekg( p, std::ios_base::end ); return *this; - } - return *this; - } - void ifstream::close() { return my->ifs.close(); } - - bool ifstream::eof()const { return !my->ifs.good(); } - - void read_file_contents( const fc::path& filename, std::string& result ) - { - const boost::filesystem::path& bfp = filename; - boost::filesystem::ifstream f( bfp, std::ios::in | std::ios::binary ); - // don't use fc::stringstream here as we need something with override for << rdbuf() - std::stringstream ss; - ss << f.rdbuf(); - result = ss.str(); - } - -} // namespace fc diff --git a/src/io/json.cpp b/src/io/json.cpp index c5a1fc989..72ba24cd1 100644 --- a/src/io/json.cpp +++ b/src/io/json.cpp @@ -1,35 +1,32 @@ #include #include -#include -#include -#include #include #include + #include #include #include #include -#include - namespace fc { // forward declarations of provided functions - template variant variant_from_stream( T& in, uint32_t max_depth ); - template char parseEscape( T& in ); - template std::string stringFromStream( T& in ); - template bool skip_white_space( T& in ); - template std::string stringFromToken( T& in ); - template variant_object objectFromStreamBase( T& in, std::function& get_key, std::function& get_value ); - template variant_object objectFromStream( T& in, uint32_t max_depth ); - template variants arrayFromStreamBase( T& in, std::function& get_value ); - template variants arrayFromStream( T& in, uint32_t max_depth ); - template variant number_from_stream( T& in ); - template variant token_from_stream( T& in ); - void escape_string( const string& str, ostream& os ); - template void to_stream( T& os, const variants& a, json::output_formatting format, uint32_t max_depth ); - template void to_stream( T& os, const variant_object& o, json::output_formatting format, uint32_t max_depth ); - template void to_stream( T& os, const variant& v, json::output_formatting format, uint32_t max_depth ); + template variant variant_from_stream( std::istream& in, uint32_t max_depth ); + char parseEscape( std::istream& in ); + std::string stringFromStream( std::istream& in ); + bool skip_white_space( std::istream& in ); + std::string stringFromToken( std::istream& in ); + variant_object objectFromStreamBase( std::istream& in, std::function& get_key, + std::function& get_value ); + template variant_object objectFromStream( std::istream& in, uint32_t max_depth ); + variants arrayFromStreamBase( std::istream& in, std::function& get_value ); + template variants arrayFromStream( std::istream& in, uint32_t max_depth ); + template variant number_from_stream( std::istream& in ); + variant token_from_stream( std::istream& in ); + void escape_string( const string& str, std::ostream& os ); + void to_stream( std::ostream& os, const variants& a, json::output_formatting format, uint32_t max_depth ); + void to_stream( std::ostream& os, const variant_object& o, json::output_formatting format, uint32_t max_depth ); + void to_stream( std::ostream& os, const variant& v, json::output_formatting format, uint32_t max_depth ); std::string pretty_print( const std::string& v, uint8_t indent ); } @@ -43,8 +40,7 @@ namespace fc namespace fc { - template - char parseEscape( T& in ) + char parseEscape( std::istream& in ) { if( in.peek() == '\\' ) { @@ -64,16 +60,17 @@ namespace fc case '\\': in.get(); return '\\'; + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: return in.get(); } } FC_RETHROW_EXCEPTIONS( info, "Stream ended with '\\'" ); } - FC_THROW_EXCEPTION( parse_error_exception, "Expected '\\'" ); + FC_THROW_EXCEPTION( parse_error_exception, "Expected '\\'" ); } - template - bool skip_white_space( T& in ) + bool skip_white_space( std::istream& in ) { bool skipped = false; while( true ) @@ -87,14 +84,15 @@ namespace fc skipped = true; in.get(); break; + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: return skipped; } } } - template - std::string stringFromStream( T& in ) + std::string stringFromStream( std::istream& in ) { fc::stringstream token; try @@ -108,7 +106,6 @@ namespace fc in.get(); while( true ) { - switch( c = in.peek() ) { case '\\': @@ -120,6 +117,8 @@ namespace fc case '"': in.get(); return token.str(); + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: token << c; in.get(); @@ -130,14 +129,13 @@ namespace fc } FC_RETHROW_EXCEPTIONS( warn, "while parsing token '${token}'", ("token", token.str() ) ); } - template - std::string stringFromToken( T& in ) + + std::string stringFromToken( std::istream& in ) { fc::stringstream token; try { - char c = in.peek(); - + char c; while( true ) { switch( c = in.peek() ) @@ -151,6 +149,8 @@ namespace fc case '\n': in.get(); return token.str(); + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: if( isalnum( c ) || c == '_' || c == '-' || c == '.' || c == ':' || c == '/' ) { @@ -175,8 +175,8 @@ namespace fc ("token", token.str() ) ); } - template - variant_object objectFromStreamBase( T& in, std::function& get_key, std::function& get_value ) + variant_object objectFromStreamBase( std::istream& in, std::function& get_key, + std::function& get_value ) { mutable_variant_object obj; try @@ -224,16 +224,19 @@ namespace fc } FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" ); } - template - variant_object objectFromStream( T& in, uint32_t max_depth ) + template + variant_object objectFromStream( std::istream& in, uint32_t max_depth ) { - std::function get_key = []( T& in ){ return stringFromStream( in ); }; - std::function get_value = [max_depth]( T& in ){ return variant_from_stream( in, max_depth ); }; - return objectFromStreamBase( in, get_key, get_value ); + std::function get_key = []( std::istream& in ){ + return stringFromStream( in ); + }; + std::function get_value = [max_depth]( std::istream& in ){ + return variant_from_stream( in, max_depth ); + }; + return objectFromStreamBase( in, get_key, get_value ); } - template - variants arrayFromStreamBase( T& in, std::function& get_value ) + variants arrayFromStreamBase( std::istream& in, std::function& get_value ) { variants ar; try @@ -262,15 +265,17 @@ namespace fc return ar; } - template - variants arrayFromStream( T& in, uint32_t max_depth ) + template + variants arrayFromStream( std::istream& in, uint32_t max_depth ) { - std::function get_value = [max_depth]( T& in ){ return variant_from_stream( in, max_depth ); }; - return arrayFromStreamBase( in, get_value ); + std::function get_value = [max_depth]( std::istream& in ){ + return variant_from_stream( in, max_depth ); + }; + return arrayFromStreamBase( in, get_value ); } - template - variant number_from_stream( T& in ) + template + variant number_from_stream( std::istream& in ) { fc::stringstream ss; @@ -288,7 +293,6 @@ namespace fc char c; while((c = in.peek()) && !done) { - switch( c ) { case '.': @@ -308,6 +312,8 @@ namespace fc case '9': ss.put( in.get() ); break; + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: if( isalnum( c ) ) { @@ -337,8 +343,8 @@ namespace fc return to_int64(str); return to_uint64(str); } - template - variant token_from_stream( T& in ) + + variant token_from_stream( std::istream& in ) { std::stringstream ss; ss.exceptions( std::ifstream::badbit ); @@ -363,6 +369,8 @@ namespace fc case 's': ss.put( in.get() ); break; + case EOF: + if( in.eof() ) FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); default: done = true; break; @@ -409,8 +417,8 @@ namespace fc } - template - variant variant_from_stream( T& in, uint32_t max_depth ) + template + variant variant_from_stream( std::istream& in, uint32_t max_depth ) { if( max_depth == 0 ) FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" ); @@ -421,9 +429,9 @@ namespace fc case '"': return stringFromStream( in ); case '{': - return objectFromStream( in, max_depth - 1 ); + return objectFromStream( in, max_depth - 1 ); case '[': - return arrayFromStream( in, max_depth - 1 ); + return arrayFromStream( in, max_depth - 1 ); case '-': case '.': case '0': @@ -436,7 +444,7 @@ namespace fc case '7': case '8': case '9': - return number_from_stream( in ); + return number_from_stream( in ); // null, true, false, or 'warning' / string case 'n': case 't': @@ -457,18 +465,17 @@ namespace fc variant json::from_string( const std::string& utf8_str, parse_type ptype, uint32_t max_depth ) { try { - fc::istream_ptr in( new fc::stringstream( utf8_str ) ); - fc::buffered_istream bin( in ); - return from_stream( bin, ptype, max_depth ); + std::stringstream in( utf8_str ); + return from_stream( in, ptype, max_depth ); } FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) ) } variants json::variants_from_string( const std::string& utf8_str, parse_type ptype, uint32_t max_depth ) { variants result; try { - fc::stringstream in( utf8_str ); + std::stringstream in( utf8_str ); while( true ) - result.push_back(json_relaxed::variant_from_stream( in, max_depth )); + result.push_back(json_relaxed::variant_from_stream( in, max_depth )); } catch ( const fc::eof_exception& ) { return result; } FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) ) @@ -479,7 +486,7 @@ namespace fc * * All other characters are printed as UTF8. */ - void escape_string( const string& str, ostream& os ) + void escape_string( const string& str, std::ostream& os ) { os << '"'; for( auto itr = str.begin(); itr != str.end(); ++itr ) @@ -547,14 +554,13 @@ namespace fc } os << '"'; } - ostream& json::to_stream( ostream& out, const std::string& str ) + std::ostream& json::to_stream( std::ostream& out, const std::string& str ) { escape_string( str, out ); return out; } - template - void to_stream( T& os, const variants& a, json::output_formatting format, uint32_t max_depth ) + void to_stream( std::ostream& os, const variants& a, json::output_formatting format, uint32_t max_depth ) { os << '['; auto itr = a.begin(); @@ -568,8 +574,8 @@ namespace fc } os << ']'; } - template - void to_stream( T& os, const variant_object& o, json::output_formatting format, uint32_t max_depth ) + + void to_stream( std::ostream& os, const variant_object& o, json::output_formatting format, uint32_t max_depth ) { os << '{'; auto itr = o.begin(); @@ -586,8 +592,7 @@ namespace fc os << '}'; } - template - void to_stream( T& os, const variant& v, json::output_formatting format, uint32_t max_depth ) + void to_stream( std::ostream& os, const variant& v, json::output_formatting format, uint32_t max_depth ) { FC_ASSERT( max_depth > 0, "Too many nested objects!" ); switch( v.get_type() ) @@ -637,7 +642,7 @@ namespace fc std::string json::to_string( const variant& v, output_formatting format, uint32_t max_depth ) { - fc::stringstream ss; + std::stringstream ss; fc::to_stream( ss, v, format, max_depth ); return ss.str(); } @@ -743,53 +748,58 @@ namespace fc if( pretty ) { auto str = json::to_pretty_string( v, format, max_depth ); - fc::ofstream o(fi); + std::ofstream o( fi.string(), std::ios_base::binary ); + FC_ASSERT( !o.fail() && !o.bad(), "Failed to open file '${f}'", ("f",fi.string()) ); o.write( str.c_str(), str.size() ); } else { - fc::ofstream o(fi); + std::ofstream o( fi.string(), std::ios_base::binary ); + FC_ASSERT( !o.fail() && !o.bad(), "Failed to open file '${f}'", ("f",fi.string()) ); fc::to_stream( o, v, format, max_depth ); } } variant json::from_file( const fc::path& p, parse_type ptype, uint32_t max_depth ) { - fc::istream_ptr in( new fc::ifstream( p ) ); - fc::buffered_istream bin( in ); - return from_stream( bin, ptype, max_depth ); + std::ifstream in( p.string() ); + FC_ASSERT( !in.fail() && !in.bad(), "Failed to open file '${f}'", ("f",p.string()) ); + return from_stream( in, ptype, max_depth ); } - variant json::from_stream( buffered_istream& in, parse_type ptype, uint32_t max_depth ) + variant json::from_stream( std::istream& in, parse_type ptype, uint32_t max_depth ) { switch( ptype ) { case legacy_parser: - return variant_from_stream( in, max_depth ); + return variant_from_stream( in, max_depth ); #ifdef WITH_EXOTIC_JSON_PARSERS case legacy_parser_with_string_doubles: - return variant_from_stream( in, max_depth ); + return variant_from_stream( in, max_depth ); case strict_parser: - return json_relaxed::variant_from_stream( in, max_depth ); + return json_relaxed::variant_from_stream( in, max_depth ); case relaxed_parser: - return json_relaxed::variant_from_stream( in, max_depth ); + return json_relaxed::variant_from_stream( in, max_depth ); #endif case broken_nul_parser: - return variant_from_stream( in, max_depth ); + return variant_from_stream( in, max_depth ); default: FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) ); } } - ostream& json::to_stream( ostream& out, const variant& v, output_formatting format, uint32_t max_depth ) + std::ostream& json::to_stream( std::ostream& out, const variant& v, output_formatting format, + uint32_t max_depth ) { fc::to_stream( out, v, format, max_depth ); return out; } - ostream& json::to_stream( ostream& out, const variants& v, output_formatting format, uint32_t max_depth ) + std::ostream& json::to_stream( std::ostream& out, const variants& v, output_formatting format, + uint32_t max_depth ) { fc::to_stream( out, v, format, max_depth ); return out; } - ostream& json::to_stream( ostream& out, const variant_object& v, output_formatting format, uint32_t max_depth ) + std::ostream& json::to_stream( std::ostream& out, const variant_object& v, output_formatting format, + uint32_t max_depth ) { fc::to_stream( out, v, format, max_depth ); return out; @@ -798,11 +808,10 @@ namespace fc bool json::is_valid( const std::string& utf8_str, parse_type ptype, uint32_t max_depth ) { if( utf8_str.size() == 0 ) return false; - fc::istream_ptr in( new fc::stringstream( utf8_str ) ); - fc::buffered_istream bin( in ); - from_stream( bin, ptype, max_depth ); - try { bin.peek(); } catch ( const eof_exception& e ) { return true; } - return false; + std::stringstream in( utf8_str ); + from_stream( in, ptype, max_depth ); + in.peek(); + return in.eof(); } } // fc diff --git a/src/log/file_appender.cpp b/src/log/file_appender.cpp index aec6bec91..2f6efd609 100644 --- a/src/log/file_appender.cpp +++ b/src/log/file_appender.cpp @@ -1,11 +1,13 @@ #include -#include #include #include #include #include #include + #include + +#include #include #include #include @@ -17,7 +19,7 @@ namespace fc { { public: config cfg; - ofstream out; + std::ofstream out; boost::mutex slock; private: @@ -41,7 +43,9 @@ namespace fc { rotate_files( true ); delete_files(); } else { - out.open( cfg.filename, std::ios_base::out | std::ios_base::app); + out.open( cfg.filename.string(), std::ios_base::app ); + FC_ASSERT( !out.fail() && !out.bad(), "Failed to open file '${f}'", + ("f",cfg.filename.string()) ); } } catch( ... ) @@ -92,7 +96,9 @@ namespace fc { out.close(); } remove_all(link_filename); // on windows, you can't delete the link while the underlying file is opened for writing - out.open( log_filename, std::ios_base::out | std::ios_base::app ); + out.open( log_filename.string(), std::ios_base::app ); + if( out.fail() || out.bad() ) + std::cerr << "Failed to open log file '" << cfg.filename.string() << "'\n"; create_hard_link(log_filename, link_filename); } } diff --git a/tests/io/json_tests.cpp b/tests/io/json_tests.cpp index 90872e864..9c75c2185 100644 --- a/tests/io/json_tests.cpp +++ b/tests/io/json_tests.cpp @@ -5,10 +5,7 @@ #include #include -#include -#include #include -#include #include @@ -40,17 +37,15 @@ static void test_fail_stream( const std::string& str ) init.close(); } try { - fc::istream_ptr in( new fc::ifstream( file.path() ) ); - fc::buffered_istream bin( in ); - fc::json::from_stream( bin ); + std::ifstream in( file.path().string() ); + fc::json::from_stream( in ); BOOST_FAIL( "json::from_stream('" + str + "') failed using ifstream" ); } catch( const fc::parse_error_exception& ) { // ignore, ok } catch( const fc::eof_exception& ) { // ignore, ok } FC_CAPTURE_LOG_AND_RETHROW( ("json::from_stream failed using ifstream")(str) ) try { - fc::istream_ptr in( new fc::stringstream( str ) ); - fc::buffered_istream bin( in ); - fc::json::from_stream( bin ); + std::stringstream in( str ); + fc::json::from_stream( in ); BOOST_FAIL( "json::from_stream('" + str + "') failed using stringstream" ); } catch( const fc::parse_error_exception& ) { // ignore, ok } catch( const fc::eof_exception& ) { // ignore, ok diff --git a/tests/io/stream_tests.cpp b/tests/io/stream_tests.cpp index 359ec9d93..130df5264 100644 --- a/tests/io/stream_tests.cpp +++ b/tests/io/stream_tests.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -75,104 +74,4 @@ BOOST_AUTO_TEST_CASE(buffered_stringstream_test) BOOST_CHECK_EQUAL( "Hello world", out1->str() ); } -BOOST_AUTO_TEST_CASE(fstream_test) -{ - fc::temp_file inf1( fc::temp_directory_path(), true ); - fc::temp_file inf2( fc::temp_directory_path(), true ); - fc::temp_file outf( fc::temp_directory_path(), true ); - - { - std::fstream init( inf1.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc ); - init.write( "Hello", 6 ); // includes trailing \0 - init.close(); - - init.open( inf2.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc ); - init.write( "world", 5 ); - init.close(); - - init.open( outf.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc ); - init.close(); - } - - fc::ifstream in1( inf1.path() ); - fc::ifstream in2( inf2.path() ); - fc::ofstream out( outf.path() ); - - std::shared_ptr buf( new char[15], [](char* p){ delete[] p; } ); - BOOST_CHECK_EQUAL( 3u, in1.readsome( buf, 3, 0 ) ); - BOOST_CHECK_EQUAL( 3u, out.writesome( buf, 3, 0 ) ); - BOOST_CHECK_EQUAL( 3u, in1.readsome( buf, 4, 0 ) ); - BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] ); - BOOST_CHECK_EQUAL( 2u, out.writesome( buf, 2, 0 ) ); - *buf = ' '; - out.writesome( buf, 1, 0 ); - BOOST_CHECK_THROW( in1.readsome( buf, 3, 0 ), fc::eof_exception ); - BOOST_CHECK_EQUAL( 5u, in2.readsome( buf, 6, 0 ) ); - BOOST_CHECK_EQUAL( 5u, out.writesome( buf, 5, 0 ) ); - BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception ); - - { - out.close(); - std::fstream test( outf.path().to_native_ansi_path(), std::fstream::in ); - test.read( (&(*buf)), 11 ); - BOOST_CHECK_EQUAL( "Hello world", std::string( (&(*buf)), 11 ) ); - BOOST_CHECK(!test.read( (&(*buf)), 11 )); - test.close(); - } - - BOOST_CHECK( in1.eof() ); - BOOST_CHECK( in2.eof() ); -} - -BOOST_AUTO_TEST_CASE(buffered_fstream_test) -{ - fc::temp_file inf1( fc::temp_directory_path(), true ); - fc::temp_file inf2( fc::temp_directory_path(), true ); - fc::temp_file outf( fc::temp_directory_path(), true ); - - { - std::fstream init( inf1.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc ); - init.write( "Hello", 6 ); // includes trailing \0 - init.close(); - - init.open( inf2.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc ); - init.write( "world", 5 ); - init.close(); - - init.open( outf.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc ); - init.close(); - } - - fc::istream_ptr in1( new fc::ifstream( inf1.path() ) ); - fc::istream_ptr in2( new fc::ifstream( inf2.path() ) ); - fc::ostream_ptr out( new fc::ofstream( outf.path() ) ); - fc::buffered_istream bin1( in1 ); - fc::buffered_istream bin2( in2 ); - fc::buffered_ostream bout( out ); - - std::shared_ptr buf( new char[15], [](char* p){ delete[] p; } ); - - BOOST_CHECK_EQUAL( 3u, bin1.readsome( buf, 3, 0 ) ); - BOOST_CHECK_EQUAL( 3u, bout.writesome( buf, 3, 0 ) ); - BOOST_CHECK_EQUAL( 'l', bin1.peek() ); - BOOST_CHECK_EQUAL( 3u, bin1.readsome( buf, 4, 0 ) ); - BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] ); - BOOST_CHECK_EQUAL( 2u, bout.writesome( buf, 2, 0 ) ); - *buf = ' '; - bout.writesome( buf, 1, 0 ); - BOOST_CHECK_THROW( bin1.readsome( buf, 3, 0 ), fc::eof_exception ); - BOOST_CHECK_EQUAL( 5u, bin2.readsome( buf, 6, 0 ) ); - BOOST_CHECK_EQUAL( 5u, bout.writesome( buf, 5, 0 ) ); - BOOST_CHECK_THROW( bin2.readsome( buf, 3, 0 ), fc::eof_exception ); - - { - bout.close(); - std::fstream test( outf.path().to_native_ansi_path(), std::fstream::in ); - test.read( (&(*buf)), 11 ); - BOOST_CHECK_EQUAL( "Hello world", std::string( (&(*buf)), 11 ) ); - BOOST_CHECK(!test.read( (&(*buf)), 11 )); - test.close(); - } -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/logging_tests.cpp b/tests/logging_tests.cpp index ef66501af..283d132b9 100644 --- a/tests/logging_tests.cpp +++ b/tests/logging_tests.cpp @@ -11,11 +11,21 @@ #include #include #include -#include -#include -#include #include +#include + +namespace fc { namespace test { + +static std::string read_file_contents( const fc::path& filename ) +{ + std::ifstream f( filename.string() ); + std::stringstream ss; + ss << f.rdbuf(); + return ss.str(); +} + +} } // fc::test BOOST_AUTO_TEST_SUITE(logging_tests) @@ -52,12 +62,11 @@ BOOST_AUTO_TEST_CASE(log_reboot) if (prev_log_filename != log_filename) { if (i > conf.rotation_interval.to_seconds()) { - std::string rez; - fc::read_file_contents(prev_log_filename, rez); + std::string rez = fc::test::read_file_contents( prev_log_filename ); std::size_t found = rez.find("my_file.cpp:" + std::to_string(i - 1)); BOOST_CHECK(found != std::string::npos); - fc::read_file_contents(log_filename, rez); + rez = fc::test::read_file_contents( log_filename ); found = rez.find("my_file.cpp:" + std::to_string(i)); BOOST_CHECK(found != std::string::npos); } From be2ab8d07f3d9add67bc03097bde8999822dbb74 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Mon, 11 Nov 2019 07:59:51 +0100 Subject: [PATCH 2/2] Added missing include --- src/filesystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 542030106..e0c89df7d 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -9,6 +9,8 @@ #include #include +#include + #ifdef _WIN32 # include # include