From 909ce98c5b05b15311426e11d03edc753c625aae Mon Sep 17 00:00:00 2001 From: Valentino Orlandi Date: Sun, 7 Jan 2024 19:14:56 +0100 Subject: [PATCH] Introduced FileHandler classes Wrapper classes to handle resources following the RAII principle --- logdoctor/utilities/gzip.cpp | 76 ++++++++++++++++++++++------- logdoctor/utilities/io.cpp | 93 ++++++++++++++++++++---------------- 2 files changed, 110 insertions(+), 59 deletions(-) diff --git a/logdoctor/utilities/gzip.cpp b/logdoctor/utilities/gzip.cpp index 3d15eb89..9a7e0960 100644 --- a/logdoctor/utilities/gzip.cpp +++ b/logdoctor/utilities/gzip.cpp @@ -24,6 +24,60 @@ #define CHUNK 16384 +//! RAII class to handle s file resource +class FileHandler +{ + FILE* file; + +public: + explicit FileHandler( const char* path, const char* mode ) + : file{ nullptr } + { + #ifdef _MSC_VER + fopen_s( &this->file, path, mode ); + #else + this->file = fopen( path, mode ); + #endif + } + + ~FileHandler() + { + if ( this->valid() ) { + fclose( this->file ); + } + } + + FileHandler(const FileHandler&) = delete; + FileHandler(FileHandler&&) = delete; + FileHandler& operator=(const FileHandler&) = delete; + FileHandler& operator=(FileHandler&&) = delete; + + inline operator FILE*() + { + return this->file; + } + + inline bool valid() const noexcept + { + return this->file != NULL; + } + + inline bool error() const noexcept + { + return ferror( this->file ); + } + + inline void close() + { + if ( fclose( this->file ) ) { + throw GenericException( "Failed to close file pointer" ); + } + this->file = nullptr; + } +}; + + + namespace GZutils { @@ -49,24 +103,16 @@ void readFile( const std::string& path, std::string& content ) } if ( successful ) { -#ifdef _MSC_VER - FILE* file; - const int err{ fopen_s( &file, path.c_str(), "rb" ) }; - /*FILE *dest = fopen ( out_path.c_str(), "wb" );*/ - if ( file == NULL || err != 0 ) { -#else - FILE* file = fopen( path.c_str(), "rb" ); - /*FILE *dest = fopen( out_path.c_str(), "wb" );*/ - if ( file == NULL ) { -#endif + FileHandler file{ path.c_str(), "rb" }; + if ( ! file.valid() ) { // unable to open the file - //throw("cannot read"); return; } + /*FILE *dest = fopen( out_path.c_str(), "wb" );*/ // decompress until deflate stream ends or end of file is reached do { strm.avail_in = static_cast(fread( in, 1, CHUNK, file )); - if ( ferror( file ) ) { + if ( file.error() ) { // error reading (void)inflateEnd( &strm ); /*successful = false;*/ @@ -111,11 +157,7 @@ void readFile( const std::string& path, std::string& content ) // clean up and return (void)inflateEnd( &strm ); successful = (ret == Z_STREAM_END) ? true : false; - if ( fclose( file ) ) { - // error while trying to close file pointer - throw GenericException( "Failed to close file pointer" ); - } - //delete file; + file.close(); // throws GenericException on failure } if ( content.empty() ) { // probably not a gzip compressed file diff --git a/logdoctor/utilities/io.cpp b/logdoctor/utilities/io.cpp index 29c1784a..3a0ea1e9 100644 --- a/logdoctor/utilities/io.cpp +++ b/logdoctor/utilities/io.cpp @@ -10,6 +10,49 @@ #include +//! RAII class to handle a file stream resource +template +class FileHandler +{ + Stream file; + +public: + explicit FileHandler( const std::string& path ) + : file{ path } + { + if ( ! this->file.is_open() ) { + throw std::ios_base::failure( "file is not open" ); + } + if ( ! this->file.good() ) { + throw std::ios_base::failure( "file is not good" ); + } + } + + ~FileHandler() + { + if ( this->file.is_open() ) { + this->file.close(); + } + } + + FileHandler(const FileHandler&) = delete; + FileHandler(FileHandler&&) = delete; + FileHandler& operator=(const FileHandler&) = delete; + FileHandler& operator=(FileHandler&&) = delete; + + inline Stream& operator*() + { + return this->file; + } + + inline void setException( const std::ios_base::iostate e ) + { + this->file.exceptions( e ); + } +}; + + + namespace IOutils { @@ -96,39 +139,22 @@ bool renameAsCopy( std::string_view path, std::error_code& err ) noexcept(true) void readFile( const std::string& path, std::string& content ) { // read the whole file - std::ifstream file; try { - /*constexpr std::size_t read_size = std::size_t(4096);*/ - file = std::ifstream(path); - if ( ! file.is_open() ) { - throw std::ios_base::failure( "file is not open" ); - } - if ( ! file.good() ) { - throw std::ios_base::failure( "file is not good" ); - } + FileHandler file{ path }; // throws std::ios_base::failure on failure // add bit exceptions - file.exceptions( std::ifstream::failbit ); - file.exceptions( std::ios_base::badbit ); + file.setException( std::ifstream::failbit ); + file.setException( std::ios_base::badbit ); // read the whole file content = std::string( - std::istreambuf_iterator( file ), + std::istreambuf_iterator( *file ), std::istreambuf_iterator() ); } catch ( const std::ios_base::failure& ) { // failed reading - if ( file.is_open() ) { - file.close(); - } throw; } catch (...) { - if ( file.is_open() ) { - file.close(); - } throw std::exception(); // already catched } - if ( file.is_open() ) { - file.close(); - } } @@ -218,37 +244,20 @@ void randomLines( const std::string& path, std::vector& lines, cons void writeOnFile( const std::string& path, std::string_view content ) { - std::ofstream file; try { - file.open( path ); - if ( ! file.is_open() ) { - throw std::ios_base::failure( "file is not open" ); - } - if ( ! file.good() ) { - throw std::ios_base::failure( "file is not good" ); - } + FileHandler file{ path }; // throws std::ios_base::failure on failure // add bit exceptions - file.exceptions( std::ifstream::failbit ); - file.exceptions( std::ios_base::badbit ); + file.setException( std::ios_base::failbit ); + file.setException( std::ios_base::badbit ); // write the content - file << content << std::endl; + *file << content << std::endl; } catch ( const std::ios_base::failure& ) { // failed writing - if ( file.is_open() ) { - file.close(); - } throw; } catch (...) { - if ( file.is_open() ) { - file.close(); - } throw std::exception(); // already catched } - - if ( file.is_open() ) { - file.close(); - } } } // namespace IOUtils