start eliminating exception use; gcc apparently bloats exceptions to

a degree that makes them not worth it
This commit is contained in:
Glenn Maynard
2004-11-30 08:12:08 +00:00
parent 641ccdbd72
commit b6eba6ac8d
5 changed files with 220 additions and 158 deletions
+37 -20
View File
@@ -436,49 +436,66 @@ int RageFile::Seek( int offset, int whence )
return Seek( (int) offset );
}
void FileReading::ReadBytes( RageFile &f, void *buf, int size )
void FileReading::ReadBytes( RageFile &f, void *buf, int size, CString &sError )
{
if( sError.size() != 0 )
return;
int ret = f.Read( buf, size );
if( ret == -1 )
throw FatalError( f.GetError() );
if( ret < size )
throw UnexpectedEOF();
sError = f.GetError();
else if( ret < size )
sError = "Unexpected end of file";
}
uint8_t FileReading::read_8( RageFile &f )
uint8_t FileReading::read_8( RageFile &f, CString &sError )
{
uint8_t val;
ReadBytes( f, &val, sizeof(uint8_t) );
return val;
ReadBytes( f, &val, sizeof(uint8_t), sError );
if( sError.size() == 0 )
return val;
else
return 0;
}
uint16_t FileReading::read_u16_le( RageFile &f )
uint16_t FileReading::read_u16_le( RageFile &f, CString &sError )
{
uint16_t val;
ReadBytes( f, &val, sizeof(uint16_t) );
return Swap16LE( val );
ReadBytes( f, &val, sizeof(uint16_t), sError );
if( sError.size() == 0 )
return Swap16LE( val );
else
return 0;
}
int16_t FileReading::read_16_le( RageFile &f )
int16_t FileReading::read_16_le( RageFile &f, CString &sError )
{
int16_t val;
ReadBytes( f, &val, sizeof(int16_t) );
return Swap16LE( val );
ReadBytes( f, &val, sizeof(int16_t), sError );
if( sError.size() == 0 )
return Swap16LE( val );
else
return 0;
}
uint32_t FileReading::read_u32_le( RageFile &f )
uint32_t FileReading::read_u32_le( RageFile &f, CString &sError )
{
uint32_t val;
ReadBytes( f, &val, sizeof(uint32_t) );
return Swap32LE( val );
ReadBytes( f, &val, sizeof(uint32_t), sError );
if( sError.size() == 0 )
return Swap32LE( val );
else
return 0;
}
int32_t FileReading::read_32_le( RageFile &f )
int32_t FileReading::read_32_le( RageFile &f, CString &sError )
{
int32_t val;
ReadBytes( f, &val, sizeof(int32_t) );
return Swap32LE( val );
ReadBytes( f, &val, sizeof(int32_t), sError );
if( sError.size() == 0 )
return Swap32LE( val );
else
return 0;
}
/*
+8 -9
View File
@@ -94,15 +94,14 @@ private:
/* Convenience wrappers for reading binary files. */
namespace FileReading
{
struct FatalError: public RageException { FatalError(const CString &str): RageException(str) { } };
struct UnexpectedEOF: public FatalError { UnexpectedEOF(): FatalError("Unexpected end of file") { } };
void ReadBytes( RageFile &f, void *buf, int size );
uint8_t read_8( RageFile &f );
int16_t read_16_le( RageFile &f );
uint16_t read_u16_le( RageFile &f );
int32_t read_32_le( RageFile &f );
uint32_t read_u32_le( RageFile &f );
/* On error, these set sError to the error message. If sError is already
* non-empty, nothing happens. */
void ReadBytes( RageFile &f, void *buf, int size, CString &sError );
uint8_t read_8( RageFile &f, CString &sError );
int16_t read_16_le( RageFile &f, CString &sError );
uint16_t read_u16_le( RageFile &f, CString &sError );
int32_t read_32_le( RageFile &f, CString &sError );
uint32_t read_u32_le( RageFile &f, CString &sError );
};
#endif
+105 -73
View File
@@ -44,7 +44,7 @@ struct WavReader
virtual ~WavReader() { }
virtual int Read( char *buf, unsigned len ) = 0;
virtual int GetLength() const = 0;
virtual void Init() = 0;
virtual bool Init() = 0;
virtual int SetPosition( int iMS ) = 0;
CString GetError() const { return m_sError; }
@@ -59,12 +59,16 @@ struct WavReaderPCM: public WavReader
WavReaderPCM( RageFile &f, const RageSoundReader_WAV::WavData &data ):
WavReader(f, data) { }
void Init()
bool Init()
{
if( m_WavData.m_iBitsPerSample != 8 && m_WavData.m_iBitsPerSample != 16 )
throw FileReading::FatalError( ssprintf("Unsupported sample size %i", m_WavData.m_iBitsPerSample) );
{
m_sError = ssprintf("Unsupported sample size %i", m_WavData.m_iBitsPerSample);
return false;
}
m_File.Seek( m_WavData.m_iDataChunkPos );
return true;
}
int Read( char *buf, unsigned len )
@@ -132,27 +136,34 @@ public:
delete[] m_pBuffer;
}
void Init()
bool Init()
{
if( m_WavData.m_iBitsPerSample != 4 )
throw FileReading::FatalError( ssprintf( "Unsupported ADPCM sample size %i", m_WavData.m_iBitsPerSample ) );
{
m_sError = ssprintf( "Unsupported ADPCM sample size %i", m_WavData.m_iBitsPerSample );
return false;
}
m_File.Seek( m_WavData.m_iExtraFmtPos );
m_iFramesPerBlock = FileReading::read_16_le( m_File );
int16_t iNumCoef = FileReading::read_16_le( m_File );
m_iFramesPerBlock = FileReading::read_16_le( m_File, m_sError );
int16_t iNumCoef = FileReading::read_16_le( m_File, m_sError );
m_iaCoef1.resize( iNumCoef );
m_iaCoef2.resize( iNumCoef );
for( int i = 0; i < iNumCoef; ++i )
{
m_iaCoef1[i] = FileReading::read_16_le( m_File );
m_iaCoef2[i] = FileReading::read_16_le( m_File );
m_iaCoef1[i] = FileReading::read_16_le( m_File, m_sError );
m_iaCoef2[i] = FileReading::read_16_le( m_File, m_sError );
}
if( m_sError.size() != 0 )
return false;
m_pBuffer = new int8_t[m_iFramesPerBlock*m_WavData.m_iChannels*sizeof(int16_t)];
m_iBufferAvail = m_iBufferUsed = 0;
m_File.Seek( m_WavData.m_iDataChunkPos );
return true;
}
void SetEOF()
@@ -162,7 +173,7 @@ public:
}
/* Return false on error, true on success (even if we hit EOF). */
void DecodeADPCMBlock()
bool DecodeADPCMBlock()
{
ASSERT_M( m_iBufferUsed == m_iBufferAvail, ssprintf("%i", m_iBufferUsed) );
@@ -171,25 +182,31 @@ public:
int8_t iPredictor[2];
int16_t iDelta[2], iSamp1[2], iSamp2[2];
for( int i = 0; i < m_WavData.m_iChannels; ++i )
iPredictor[i] = FileReading::read_8( m_File );
iPredictor[i] = FileReading::read_8( m_File, m_sError );
for( int i = 0; i < m_WavData.m_iChannels; ++i )
iDelta[i] = FileReading::read_16_le( m_File );
iDelta[i] = FileReading::read_16_le( m_File, m_sError );
for( int i = 0; i < m_WavData.m_iChannels; ++i )
iSamp1[i] = FileReading::read_16_le( m_File );
iSamp1[i] = FileReading::read_16_le( m_File, m_sError );
for( int i = 0; i < m_WavData.m_iChannels; ++i )
iSamp2[i] = FileReading::read_16_le( m_File );
iSamp2[i] = FileReading::read_16_le( m_File, m_sError );
if( m_sError.size() != 0 )
return false;
if( m_File.Tell() >= m_WavData.m_iDataChunkSize+m_WavData.m_iDataChunkPos || m_File.AtEOF() )
return; /* past the data chunk */
CString sError;
return true; /* past the data chunk */
int16_t *pBuffer = (int16_t *) m_pBuffer;
int iCoef1[2], iCoef2[2];
for( int i = 0; i < m_WavData.m_iChannels; ++i )
{
if( iPredictor[i] >= (int) m_iaCoef1.size() )
throw FileReading::FatalError( "Predictor out of range" );
{
LOG->Trace( "%s: predictor out of range", m_File.GetPath().c_str() );
/* XXX: silence this block? */
iPredictor[i] = 0;
}
iCoef1[i] = m_iaCoef1[iPredictor[i]];
iCoef2[i] = m_iaCoef2[iPredictor[i]];
@@ -203,7 +220,12 @@ public:
int iBlockSize = m_File.Read( pBuf, iMaxSize );
if( iBlockSize == 0 )
return;
return true;
if( iBlockSize == -1 )
{
m_sError = m_File.GetError();
return false;
}
for( int i = 0; i < m_WavData.m_iChannels; ++i )
pBuffer[m_iBufferAvail++] = iSamp2[i];
@@ -254,6 +276,7 @@ public:
}
m_iBufferAvail *= sizeof(int16_t);
return true;
}
int Read( char *buf, unsigned len )
@@ -263,12 +286,8 @@ public:
{
if( m_iBufferUsed == m_iBufferAvail )
{
try {
DecodeADPCMBlock();
} catch( const FileReading::FatalError &err ) {
m_sError = err.what();
if( !DecodeADPCMBlock() )
return -1;
}
}
if( m_iBufferAvail == 0 )
break; /* EOF */
@@ -320,12 +339,8 @@ public:
m_File.Seek( iByte+m_WavData.m_iDataChunkPos );
}
try {
DecodeADPCMBlock();
} catch( const FileReading::FatalError &err ) {
m_sError = err.what();
if( !DecodeADPCMBlock() )
return -1;
}
const int iRemainingFrames = iFrame - iBlock*m_iFramesPerBlock;
m_iBufferUsed = iRemainingFrames * m_WavData.m_iChannels * sizeof(int16_t);
@@ -338,34 +353,62 @@ public:
return iMS;
}
};
struct NotWAV: public RageException { NotWAV(): RageException("not a WAV") { } };
CString ReadString( RageFile &f, int iSize )
CString ReadString( RageFile &f, int iSize, CString &sError )
{
if( sError.size() != 0 )
return "";
CString sBuf;
char *pBuf = sBuf.GetBuffer( iSize );
FileReading::ReadBytes( f, pBuf, iSize );
FileReading::ReadBytes( f, pBuf, iSize, sError );
sBuf.ReleaseBuffer( iSize );
return sBuf;
}
void RageSoundReader_WAV::OpenInternal()
#define FATAL_ERROR(s) \
{ \
if( sError.size() == 0 ) sError = (s); \
SetError( sError ); \
return OPEN_FATAL_ERROR; \
}
SoundReader_FileReader::OpenResult RageSoundReader_WAV::Open( CString filename_ )
{
m_sFilename = filename_;
CString sError;
if( !m_File.Open( m_sFilename ) )
FATAL_ERROR( ssprintf("wav: opening \"%s\" failed: %s", m_sFilename.c_str(), m_File.GetError().c_str()) );
/* RIFF header: */
if( ReadString( m_File, 4 ) != "RIFF" )
throw NotWAV();
FileReading::read_32_le( m_File ); /* file size */
if( ReadString( m_File, 4 ) != "WAVE" )
throw NotWAV();
if( ReadString( m_File, 4, sError ) != "RIFF" )
{
SetError( "Not a WAV file" );
return OPEN_UNKNOWN_FILE_FORMAT;
}
FileReading::read_32_le( m_File, sError ); /* file size */
if( ReadString( m_File, 4, sError ) != "WAVE" )
{
SetError( "Not a WAV file" );
return OPEN_UNKNOWN_FILE_FORMAT;
}
int16_t iFormatTag = 0;
bool bGotFormatChunk = false, bGotDataChunk = false;
while( !bGotFormatChunk || !bGotDataChunk )
{
CString ChunkID = ReadString( m_File, 4 );
CString ChunkID = ReadString( m_File, 4, sError );
int32_t iChunkSize = FileReading::read_32_le( m_File, sError );
int32_t iChunkSize = FileReading::read_32_le( m_File );
if( sError.size() != 0 )
{
SetError( sError );
return OPEN_FATAL_ERROR;
}
int iNextChunk = m_File.Tell() + iChunkSize;
/* Chunks are always word-aligned: */
@@ -376,19 +419,19 @@ void RageSoundReader_WAV::OpenInternal()
if( bGotFormatChunk )
LOG->Warn( "File %s has more than one fmt chunk", m_File.GetPath().c_str() );
iFormatTag = FileReading::read_16_le( m_File );
m_WavData.m_iChannels = FileReading::read_16_le( m_File );
m_WavData.m_iSampleRate = FileReading::read_32_le( m_File );
FileReading::read_32_le( m_File ); /* BytesPerSec */
m_WavData.m_iBlockAlign = FileReading::read_16_le( m_File );
m_WavData.m_iBitsPerSample = FileReading::read_16_le( m_File );
m_WavData.m_iExtraFmtBytes = FileReading::read_16_le( m_File );
iFormatTag = FileReading::read_16_le( m_File, sError );
m_WavData.m_iChannels = FileReading::read_16_le( m_File, sError );
m_WavData.m_iSampleRate = FileReading::read_32_le( m_File, sError );
FileReading::read_32_le( m_File, sError ); /* BytesPerSec */
m_WavData.m_iBlockAlign = FileReading::read_16_le( m_File, sError );
m_WavData.m_iBitsPerSample = FileReading::read_16_le( m_File, sError );
m_WavData.m_iExtraFmtBytes = FileReading::read_16_le( m_File, sError );
if( m_WavData.m_iChannels < 1 || m_WavData.m_iChannels > 2 )
throw FileReading::FatalError( ssprintf( "Unsupported channel count: %i", m_WavData.m_iChannels) );
FATAL_ERROR( ssprintf( "Unsupported channel count: %i", m_WavData.m_iChannels) );
if( m_WavData.m_iSampleRate < 4000 || m_WavData.m_iSampleRate > 100000 ) /* unlikely */
throw FileReading::FatalError( ssprintf( "Invalid sample rate: %i", m_WavData.m_iSampleRate) );
FATAL_ERROR( ssprintf( "Invalid sample rate: %i", m_WavData.m_iSampleRate) );
m_WavData.m_iExtraFmtPos = m_File.Tell();
@@ -415,6 +458,12 @@ void RageSoundReader_WAV::OpenInternal()
m_File.Seek( iNextChunk );
}
if( sError.size() != 0 )
{
SetError( sError );
return OPEN_FATAL_ERROR;
}
switch( iFormatTag )
{
case 1: // PCM
@@ -425,31 +474,14 @@ void RageSoundReader_WAV::OpenInternal()
break;
case 85: // MP3
/* Return unknown, so other decoders will be tried. MAD can read MP3s embedded in WAVs. */
throw NotWAV();
default:
throw FileReading::FatalError( ssprintf( "Unsupported data format %i", iFormatTag) );
}
m_pImpl->Init();
}
SoundReader_FileReader::OpenResult RageSoundReader_WAV::Open( CString filename_ )
{
m_sFilename = filename_;
if( !m_File.Open( m_sFilename ) )
{
SetError( ssprintf("wav: opening \"%s\" failed: %s", m_sFilename.c_str(), m_File.GetError().c_str()) );
return OPEN_FATAL_ERROR;
}
try {
OpenInternal();
} catch( const NotWAV &err ) {
SetError( err.what() );
return OPEN_UNKNOWN_FILE_FORMAT;
} catch( const FileReading::FatalError &err ) {
SetError( err.what() );
default:
FATAL_ERROR( ssprintf( "Unsupported data format %i", iFormatTag) );
}
if( !m_pImpl->Init() )
{
SetError( m_pImpl->GetError() );
return OPEN_FATAL_ERROR;
}
-1
View File
@@ -37,7 +37,6 @@ private:
WavReader *m_pImpl;
void OpenInternal();
int SetPosition( int ms );
};
+70 -55
View File
@@ -16,56 +16,68 @@ enum
COMP_BI_BITFIELDS
};
struct NotBMP: public RageException { NotBMP(): RageException("not a BMP") { } };
static RageSurface *LoadBMP( RageFile &f, RageSurface *&ret )
/* When returning error, the first error encountered takes priority. */
#define FATAL_ERROR(s) \
{ \
if( sError.size() == 0 ) sError = (s); \
return RageSurfaceUtils::OPEN_FATAL_ERROR; \
}
static RageSurfaceUtils::OpenResult LoadBMP( RageFile &f, RageSurface *&img, CString &sError )
{
char magic[2];
ReadBytes( f, magic, 2 );
ReadBytes( f, magic, 2, sError );
if( magic[0] != 'B' || magic[1] != 'M' )
throw NotBMP();
{
sError = "not a BMP";
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT;
}
img = NULL;
read_u32_le( f, sError ); /* file size */
read_u32_le( f, sError ); /* unused */
uint32_t iDataOffset = read_u32_le( f, sError );
uint32_t iHeaderSize = read_u32_le( f, sError );
read_u32_le( f ); /* file size */
read_u32_le( f ); /* unused */
uint32_t iDataOffset = read_u32_le( f );
uint32_t iHeaderSize = read_u32_le( f );
uint32_t iWidth, iHeight, iPlanes, iBPP, iCompression = COMP_BI_RGB, iColors = 0;
if( iHeaderSize == 12 )
{
/* OS/2 format */
iWidth = read_u16_le( f );
iHeight = read_u16_le( f );
iPlanes = read_u16_le( f );
iBPP = read_u16_le( f );
iWidth = read_u16_le( f, sError );
iHeight = read_u16_le( f, sError );
iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f, sError );
}
else if( iHeaderSize == 40 )
{
iWidth = read_u32_le( f );
iHeight = read_u32_le( f );
iPlanes = read_u16_le( f );
iBPP = read_u16_le( f );
iCompression = read_u32_le( f );
read_u32_le( f ); /* bitmap size */
read_u32_le( f ); /* horiz resolution */
read_u32_le( f ); /* vert resolution */
iColors = read_u32_le( f );
read_u32_le( f ); /* "important" colors */
iWidth = read_u32_le( f, sError );
iHeight = read_u32_le( f, sError );
iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f, sError );
iCompression = read_u32_le( f, sError );
read_u32_le( f, sError ); /* bitmap size */
read_u32_le( f, sError ); /* horiz resolution */
read_u32_le( f, sError ); /* vert resolution */
iColors = read_u32_le( f, sError );
read_u32_le( f, sError ); /* "important" colors */
}
else
throw FatalError( ssprintf( "expected header size of 40, got %u", iHeaderSize ) );
FATAL_ERROR( ssprintf( "expected header size of 40, got %u", iHeaderSize ) );
if( iBPP <= 8 && iColors == 0 )
iColors = 1 << iBPP;
if( iPlanes != 1 )
throw FatalError( ssprintf( "expected one plane, got %u", iPlanes ) );
FATAL_ERROR( ssprintf( "expected one plane, got %u", iPlanes ) );
if( iBPP != 1 && iBPP != 4 && iBPP != 8 && iBPP != 16 && iBPP != 24 && iBPP != 32 )
throw FatalError( ssprintf( "unsupported bpp %u", iBPP ) );
FATAL_ERROR( ssprintf( "unsupported bpp %u", iBPP ) );
if( iCompression != COMP_BI_RGB && iCompression != COMP_BI_BITFIELDS )
throw FatalError( ssprintf( "unsupported compression %u", iCompression ) );
FATAL_ERROR( ssprintf( "unsupported compression %u", iCompression ) );
if( iCompression == COMP_BI_BITFIELDS && iBPP <= 8 )
throw FatalError( ssprintf( "BI_BITFIELDS unexpected with bpp %u", iBPP ) );
FATAL_ERROR( ssprintf( "BI_BITFIELDS unexpected with bpp %u", iBPP ) );
int iFileBPP = iBPP;
iBPP = max( iBPP, 8u );
@@ -92,36 +104,43 @@ static RageSurface *LoadBMP( RageFile &f, RageSurface *&ret )
if( iCompression == COMP_BI_BITFIELDS )
{
Rmask = read_u32_le( f );
Gmask = read_u32_le( f );
Bmask = read_u32_le( f );
Rmask = read_u32_le( f, sError );
Gmask = read_u32_le( f, sError );
Bmask = read_u32_le( f, sError );
}
RageSurface *img = CreateSurface( iWidth, iHeight, iBPP, Rmask, Gmask, Bmask, Amask );
/* Stop on error before we use any of the values we just read. */
if( sError.size() != 0 )
return RageSurfaceUtils::OPEN_FATAL_ERROR;
img = CreateSurface( iWidth, iHeight, iBPP, Rmask, Gmask, Bmask, Amask );
try { /* file reading may throw */
if( iBPP == 8 )
{
RageSurfaceColor Palette[256];
ZERO( Palette );
if( iColors > 256 )
throw FatalError( ssprintf( "unexpected colors %i", iColors ) );
FATAL_ERROR( ssprintf( "unexpected colors %i", iColors ) );
for( unsigned i = 0; i < iColors; ++i )
{
Palette[i].b = read_8( f );
Palette[i].g = read_8( f );
Palette[i].r = read_8( f );
Palette[i].b = read_8( f, sError );
Palette[i].g = read_8( f, sError );
Palette[i].r = read_8( f, sError );
Palette[i].a = 0xFF;
/* Windows BMP palettes are padded to 32bpp. */
if( iHeaderSize == 40 )
read_8( f );
read_8( f, sError );
}
memcpy( img->fmt.palette->colors, Palette, sizeof(Palette) );
}
/* Stop on error before we seek, so we don't return the wrong error message. */
if( sError.size() != 0 )
return RageSurfaceUtils::OPEN_FATAL_ERROR;
int iFilePitch = iFileBPP * iWidth; // in bits
iFilePitch = (iFilePitch+7) / 8; // in bytes: round up
iFilePitch = (iFilePitch+3) & ~3; // round up a multiple of 4
@@ -129,9 +148,9 @@ try { /* file reading may throw */
{
int ret = f.Seek( iDataOffset );
if( ret == -1 )
throw FatalError( f.GetError() );
FATAL_ERROR( f.GetError() );
if( ret != (int) iDataOffset )
throw UnexpectedEOF();
FATAL_ERROR( "Unexpected end of file" );
}
for( int y = (int) iHeight-1; y >= 0; --y )
@@ -165,15 +184,11 @@ try { /* file reading may throw */
else
memcpy( pRow, buf.data(), img->pitch );
}
} catch(...) {
delete img;
throw;
return sError.size() != 0? RageSurfaceUtils::OPEN_FATAL_ERROR: RageSurfaceUtils::OPEN_OK;
}
return img;
}
RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const CString &sPath, RageSurface *&ret, bool bHeaderOnly, CString &error )
RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const CString &sPath, RageSurface *&img, bool bHeaderOnly, CString &error )
{
RageFile f;
@@ -183,17 +198,17 @@ RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const CString &sPath, RageSur
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
try {
ret = LoadBMP( f, ret );
} catch( const NotBMP & ) {
error = "not a BMP";
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT;
} catch( const FatalError &err ) {
error = err.what();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
RageSurfaceUtils::OpenResult ret;
img = NULL;
ret = LoadBMP( f, img, error );
if( ret != RageSurfaceUtils::OPEN_OK && img != NULL )
{
delete img;
img = NULL;
}
return RageSurfaceUtils::OPEN_OK;
return ret;
}
/*