/******************************************************************************/ /* FILES **********************************************************************/ /******************************************************************************/ #include using namespace ebcl; /*= T_File ==================================================================*/ T_File::T_File( ) : path_( ) , file_( nullptr ) { } T_File::T_File( T_FSPath const& path , const E_FileMode mode ) : path_( path ) , mode_( mode ) , file_( nullptr ) { } T_File::T_File( T_File&& other ) noexcept : T_File( ) { swap( *this , other ); } T_File& T_File::operator= ( T_File&& other ) noexcept { swap( *this , other ); return *this; } /*---------------------------------------------------------------------------*/ void T_File::open( ) { if ( file_ != nullptr ) { return; } // Copy file path to C string const T_Buffer< char > path( path_.toString( ).toOSString( ) ); // Select the right mode char const* const mode( ([this]() { switch ( mode_ ) { case E_FileMode::READ_ONLY: return "rb"; case E_FileMode::READ_WRITE: return "rb+"; case E_FileMode::OVERWRITE: return "wb+"; } std::abort( ); })( ) ); // Open the file #ifdef WIN32_ file_ = _wfopen( ( wchar_t const* ) &path[ 0 ] , mode ); #else file_ = fopen( &path[ 0 ] , mode ); #endif if ( file_ == nullptr ) { throw X_StreamError( errno ); } // Get initial size if ( fseek( file_ , 0 , SEEK_END ) != 0 ) { auto err( errno ); close( ); throw X_StreamError( err ); } off_t sz( ftell( file_ ) ); if ( sz < 0 || fseek( file_ , 0 , SEEK_SET ) != 0 ) { auto err( errno ); close( ); throw X_StreamError( err ); } pos_ = 0; size_ = sz; } void T_File::close( ) noexcept { if ( file_ != nullptr ) { fclose( file_ ); file_ = nullptr; } } /*---------------------------------------------------------------------------*/ void T_File::position( size_t position , bool fromEnd ) { open( ); const auto rv( fromEnd ? fseek( file_ , -position , SEEK_END ) : fseek( file_ , +position , SEEK_SET ) ); if ( rv < 0 ) { throw X_StreamError( errno ); } pos_ = rv; } void T_File::move( ssize_t offset ) { open( ); const auto rv( fseek( file_ , offset , SEEK_CUR ) ); if ( rv < 0 ) { throw X_StreamError( errno ); } pos_ = rv; } /*---------------------------------------------------------------------------*/ size_t T_File::read( void* data , size_t size ) { open( ); if ( pos_ >= size_ ) { throw X_StreamError( E_StreamError::END ); } const auto rv( fread( data , 1 , size , file_ ) ); if ( ferror( file_ ) ) { throw X_StreamError( errno ); } else { pos_ += rv; return rv; } } /*---------------------------------------------------------------------------*/ size_t T_File::write( void const* data , size_t size ) { if ( mode_ == E_FileMode::READ_ONLY ) { throw X_StreamError( E_StreamError::NOT_SUPPORTED ); } open( ); auto rv( fwrite( data , 1 , size , file_ ) ); if ( ferror( file_ ) ) { throw X_StreamError( errno ); } else { pos_ += rv; if ( pos_ > size_ ) { size_ = pos_; } return rv; } } /*---------------------------------------------------------------------------*/ void T_File::flush( ) { if ( !isOpen( ) || mode_ == E_FileMode::READ_ONLY ) { return; } fflush( file_ ); } /*= T_FileInputStream =======================================================*/ T_FileInputStream::T_FileInputStream( T_File& file , ssize_t offset , size_t limit ) : A_InputStream( 0 , 0 ) , fileRaw_( &file ) , fileOwned_( ) { init( offset , limit ); } T_FileInputStream::T_FileInputStream( OP_File&& file , ssize_t offset , size_t limit ) : A_InputStream( 0 , 0 ) , fileRaw_( nullptr ) , fileOwned_( std::move( file ) ) { file.clear( ); init( offset , limit ); } /*---------------------------------------------------------------------------*/ T_FileInputStream::T_FileInputStream( T_FileInputStream const& other ) : A_InputStream( other.position( ) , other.size( ) ) , fileRaw_( &( other.file( ) ) ) , fileOwned_( ) , start_( other.start_ ) { } T_FileInputStream& T_FileInputStream::operator= ( T_FileInputStream const& other ) { position_ = other.position_; size_ = other.size_; fileRaw_ = &( other.file( ) ); fileOwned_ = OP_File( ); start_ = other.start_; return *this; } /*---------------------------------------------------------------------------*/ void T_FileInputStream::swap( T_FileInputStream& rhs ) noexcept { using std::swap; swap( size_ , rhs.size_ ); swap( position_ , rhs.position_ ); swap( fileRaw_ , rhs.fileRaw_ ); swap( fileOwned_ , rhs.fileOwned_ ); swap( start_ , rhs.start_ ); } /*---------------------------------------------------------------------------*/ size_t T_FileInputStream::read( void* data , size_t size ) { if ( position_ >= size_ ) { throw X_StreamError( E_StreamError::END ); } auto& f( file( ) ); f.open( ); if ( f.position( ) != start_ + position_ ) { f.position( start_ + position_ ); } const size_t rSize( std::min( size , size_ - position_ ) ); const auto r( f.read( data , rSize ) ); position_ += r; return r; } /*---------------------------------------------------------------------------*/ void T_FileInputStream::init( ssize_t offset , size_t limit ) { auto& f( file( ) ); f.open( ); const ssize_t start( f.position( ) + offset ); if ( start < 0 || start > ssize_t( f.size( ) ) ) { throw X_StreamError( E_StreamError::INVALID_POSITION ); } start_ = start; size_ = std::min( f.size( ) - start , limit ); } /*= T_FileOutputStream =======================================================*/ T_FileOutputStream::T_FileOutputStream( T_File& file , ssize_t offset ) : A_OutputStream( 0 ) , fileRaw_( &file ) , fileOwned_( ) { init( offset ); } T_FileOutputStream::T_FileOutputStream( OP_File&& file , ssize_t offset ) : A_OutputStream( 0 ) , fileRaw_( nullptr ) , fileOwned_( std::move( file ) ) { init( offset ); } /*---------------------------------------------------------------------------*/ T_FileOutputStream::T_FileOutputStream( T_FileOutputStream const& other ) : A_OutputStream( other.position( ) ) , fileRaw_( &other.file( ) ) , fileOwned_( ) , start_( other.start_ ) { } T_FileOutputStream& T_FileOutputStream::operator= ( T_FileOutputStream const& other ) { position_ = other.position_; fileRaw_ = &other.file( ); fileOwned_ = OP_File( ); start_ = other.start_; return *this; } /*---------------------------------------------------------------------------*/ inline void T_FileOutputStream::swap( T_FileOutputStream& rhs ) noexcept { using std::swap; swap( position_ , rhs.position_ ); swap( fileRaw_ , rhs.fileRaw_ ); swap( fileOwned_ , rhs.fileOwned_ ); swap( start_ , rhs.start_ ); } /*---------------------------------------------------------------------------*/ size_t T_FileOutputStream::write( void const* data , size_t size ) { auto& f( file( ) ); f.open( ); if ( f.position( ) != start_ + position_ ) { f.position( start_ + position_ ); } const auto w( f.write( data , size ) ); position_ += w; return w; } /*---------------------------------------------------------------------------*/ void T_FileOutputStream::flush( ) { file( ).flush( ); } /*---------------------------------------------------------------------------*/ void T_FileOutputStream::init( ssize_t offset ) { auto& f( file( ) ); if ( f.mode( ) == E_FileMode::READ_ONLY ) { throw X_StreamError( E_StreamError::NOT_SUPPORTED ); } const ssize_t start( f.position( ) + offset ); if ( start < 0 || start > ssize_t( f.size( ) ) ) { throw X_StreamError( E_StreamError::INVALID_POSITION ); } start_ = start; }