corelib/src/Files.cc

327 lines
7.7 KiB
C++

/******************************************************************************/
/* FILES **********************************************************************/
/******************************************************************************/
#include <ebcl/Files.hh>
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 , path_ );
}
// Get initial size
if ( fseek( file_ , 0 , SEEK_END ) != 0 ) {
auto err( errno );
close( );
throw X_StreamError( err , path_ );
}
off_t sz( ftell( file_ ) );
if ( sz < 0 || fseek( file_ , 0 , SEEK_SET ) != 0 ) {
auto err( errno );
close( );
throw X_StreamError( err , path_ );
}
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 , path_ );
}
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 , path_ );
}
pos_ = rv;
}
/*---------------------------------------------------------------------------*/
size_t T_File::read( void* data , size_t size )
{
open( );
if ( pos_ >= size_ ) {
throw X_StreamError( E_StreamError::END , path_ );
}
const auto rv( fread( data , 1 , size , file_ ) );
if ( ferror( file_ ) ) {
throw X_StreamError( errno , path_ );
} 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 , path_ );
}
open( );
auto rv( fwrite( data , 1 , size , file_ ) );
if ( ferror( file_ ) ) {
throw X_StreamError( errno , path_ );
} 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 )
{
auto& f( file( ) );
if ( position_ >= size_ ) {
throw X_StreamError( E_StreamError::END , f.path( ) );
}
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 ,
f.path( ) );
}
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 ,
f.path( ) );
}
const ssize_t start( f.position( ) + offset );
if ( start < 0 || start > ssize_t( f.size( ) ) ) {
throw X_StreamError( E_StreamError::INVALID_POSITION ,
f.path( ) );
}
start_ = start;
}