mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-24 04:24:09 +00:00
269 lines
4.8 KiB
C++
269 lines
4.8 KiB
C++
|
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
|
||
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||
|
|
||
|
#include "file.hh"
|
||
|
|
||
|
#include <cstring>
|
||
|
#include <cerrno>
|
||
|
|
||
|
namespace File {
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
// We employ a writing buffer to considerably speed up file operations when
|
||
|
// they consists of many small writes. The default size for the buffer is 64k
|
||
|
WriteBufferSize = 65536
|
||
|
};
|
||
|
|
||
|
void Class::open( char const * filename, char const * mode ) throw( exCantOpen )
|
||
|
{
|
||
|
f = fopen( filename, mode );
|
||
|
|
||
|
if ( !f )
|
||
|
throw exCantOpen( std::string( filename ) + ": " + strerror( errno ) );
|
||
|
}
|
||
|
|
||
|
Class::Class( char const * filename, char const * mode ) throw( exCantOpen ):
|
||
|
writeBuffer( 0 )
|
||
|
{
|
||
|
open( filename, mode );
|
||
|
}
|
||
|
|
||
|
Class::Class( std::string const & filename, char const * mode )
|
||
|
throw( exCantOpen ): writeBuffer( 0 )
|
||
|
{
|
||
|
open( filename.c_str(), mode );
|
||
|
}
|
||
|
|
||
|
void Class::read( void * buf, size_t size ) throw( exReadError, exWriteError )
|
||
|
{
|
||
|
if ( !size )
|
||
|
return;
|
||
|
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
size_t result = fread( buf, size, 1, f );
|
||
|
|
||
|
if ( result != 1 )
|
||
|
throw exReadError();
|
||
|
}
|
||
|
|
||
|
size_t Class::readRecords( void * buf, size_t size, size_t count ) throw( exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
return fread( buf, size, count, f );
|
||
|
}
|
||
|
|
||
|
void Class::write( void const * buf, size_t size ) throw( exWriteError )
|
||
|
{
|
||
|
if ( !size )
|
||
|
return;
|
||
|
|
||
|
if ( size >= WriteBufferSize )
|
||
|
{
|
||
|
// If the write is large, there's not much point in buffering
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
size_t result = fwrite( buf, size, 1, f );
|
||
|
|
||
|
if ( result != 1 )
|
||
|
throw exWriteError();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !writeBuffer )
|
||
|
{
|
||
|
// Allocate the writing buffer since we don't have any yet
|
||
|
writeBuffer = new char[ WriteBufferSize ];
|
||
|
writeBufferLeft = WriteBufferSize;
|
||
|
}
|
||
|
|
||
|
size_t toAdd = size < writeBufferLeft ? size : writeBufferLeft;
|
||
|
|
||
|
memcpy( writeBuffer + ( WriteBufferSize - writeBufferLeft ),
|
||
|
buf, toAdd );
|
||
|
|
||
|
size -= toAdd;
|
||
|
writeBufferLeft -= toAdd;
|
||
|
|
||
|
if ( !writeBufferLeft ) // Out of buffer? Flush it.
|
||
|
{
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
if ( size ) // Something's still left? Add to buffer.
|
||
|
{
|
||
|
memcpy( writeBuffer, (char const *)buf + toAdd, size );
|
||
|
writeBufferLeft -= size;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
size_t Class::writeRecords( void const * buf, size_t size, size_t count )
|
||
|
throw( exWriteError )
|
||
|
{
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
return fwrite( buf, size, count, f );
|
||
|
}
|
||
|
|
||
|
char * Class::gets( char * s, int size, bool stripNl )
|
||
|
throw( exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
char * result = fgets( s, size, f );
|
||
|
|
||
|
if ( result && stripNl )
|
||
|
{
|
||
|
size_t len = strlen( result );
|
||
|
|
||
|
char * last = result + len;
|
||
|
|
||
|
while( len-- )
|
||
|
{
|
||
|
--last;
|
||
|
|
||
|
if ( *last == '\n' || *last == '\r' )
|
||
|
*last = 0;
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
std::string Class::gets( bool stripNl ) throw( exReadError, exWriteError )
|
||
|
{
|
||
|
char buf[ 1024 ];
|
||
|
|
||
|
if ( !gets( buf, sizeof( buf ), stripNl ) )
|
||
|
throw exReadError();
|
||
|
|
||
|
return std::string( buf );
|
||
|
}
|
||
|
|
||
|
void Class::seek( long offset ) throw( exSeekError, exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
if ( fseek( f, offset, SEEK_SET ) != 0 )
|
||
|
throw exSeekError();
|
||
|
}
|
||
|
|
||
|
void Class::seekCur( long offset ) throw( exSeekError, exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
if ( fseek( f, offset, SEEK_CUR ) != 0 )
|
||
|
throw exSeekError();
|
||
|
}
|
||
|
|
||
|
void Class::seekEnd( long offset ) throw( exSeekError, exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
if ( fseek( f, offset, SEEK_END ) != 0 )
|
||
|
throw exSeekError();
|
||
|
}
|
||
|
|
||
|
void Class::rewind() throw( exSeekError, exWriteError )
|
||
|
{
|
||
|
seek( 0 );
|
||
|
}
|
||
|
|
||
|
size_t Class::tell() throw( exSeekError )
|
||
|
{
|
||
|
long result = ftell( f );
|
||
|
|
||
|
if ( result == -1 )
|
||
|
throw exSeekError();
|
||
|
|
||
|
if ( writeBuffer )
|
||
|
result += ( WriteBufferSize - writeBufferLeft );
|
||
|
|
||
|
return ( size_t ) result;
|
||
|
}
|
||
|
|
||
|
bool Class::eof() throw( exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer )
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
return feof( f );
|
||
|
}
|
||
|
|
||
|
FILE * Class::file() throw( exWriteError )
|
||
|
{
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
FILE * Class::release() throw( exWriteError )
|
||
|
{
|
||
|
releaseWriteBuffer();
|
||
|
|
||
|
FILE * c = f;
|
||
|
|
||
|
f = 0;
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
void Class::close() throw( exWriteError )
|
||
|
{
|
||
|
fclose( release() );
|
||
|
}
|
||
|
|
||
|
Class::~Class() throw()
|
||
|
{
|
||
|
if ( f )
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
releaseWriteBuffer();
|
||
|
}
|
||
|
catch( exWriteError & )
|
||
|
{
|
||
|
}
|
||
|
fclose( f );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Class::flushWriteBuffer() throw( exWriteError )
|
||
|
{
|
||
|
if ( writeBuffer && writeBufferLeft != WriteBufferSize )
|
||
|
{
|
||
|
size_t result = fwrite( writeBuffer, WriteBufferSize - writeBufferLeft, 1, f );
|
||
|
|
||
|
if ( result != 1 )
|
||
|
throw exWriteError();
|
||
|
|
||
|
writeBufferLeft = WriteBufferSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Class::releaseWriteBuffer() throw( exWriteError )
|
||
|
{
|
||
|
flushWriteBuffer();
|
||
|
|
||
|
if ( writeBuffer )
|
||
|
{
|
||
|
delete [] writeBuffer;
|
||
|
|
||
|
writeBuffer = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|