327 lines
7.7 KiB
C++
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;
|
|
}
|