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 ); 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 ); int ret = f.Read( buf, size );
if( ret == -1 ) if( ret == -1 )
throw FatalError( f.GetError() ); sError = f.GetError();
else if( ret < size )
if( ret < size ) sError = "Unexpected end of file";
throw UnexpectedEOF();
} }
uint8_t FileReading::read_8( RageFile &f ) uint8_t FileReading::read_8( RageFile &f, CString &sError )
{ {
uint8_t val; uint8_t val;
ReadBytes( f, &val, sizeof(uint8_t) ); ReadBytes( f, &val, sizeof(uint8_t), sError );
return val; 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; uint16_t val;
ReadBytes( f, &val, sizeof(uint16_t) ); ReadBytes( f, &val, sizeof(uint16_t), sError );
return Swap16LE( val ); 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; int16_t val;
ReadBytes( f, &val, sizeof(int16_t) ); ReadBytes( f, &val, sizeof(int16_t), sError );
return Swap16LE( val ); 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; uint32_t val;
ReadBytes( f, &val, sizeof(uint32_t) ); ReadBytes( f, &val, sizeof(uint32_t), sError );
return Swap32LE( val ); 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; int32_t val;
ReadBytes( f, &val, sizeof(int32_t) ); ReadBytes( f, &val, sizeof(int32_t), sError );
return Swap32LE( val ); 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. */ /* Convenience wrappers for reading binary files. */
namespace FileReading namespace FileReading
{ {
struct FatalError: public RageException { FatalError(const CString &str): RageException(str) { } }; /* On error, these set sError to the error message. If sError is already
struct UnexpectedEOF: public FatalError { UnexpectedEOF(): FatalError("Unexpected end of file") { } }; * non-empty, nothing happens. */
void ReadBytes( RageFile &f, void *buf, int size, CString &sError );
void ReadBytes( RageFile &f, void *buf, int size ); uint8_t read_8( RageFile &f, CString &sError );
uint8_t read_8( RageFile &f ); int16_t read_16_le( RageFile &f, CString &sError );
int16_t read_16_le( RageFile &f ); uint16_t read_u16_le( RageFile &f, CString &sError );
uint16_t read_u16_le( RageFile &f ); int32_t read_32_le( RageFile &f, CString &sError );
int32_t read_32_le( RageFile &f ); uint32_t read_u32_le( RageFile &f, CString &sError );
uint32_t read_u32_le( RageFile &f );
}; };
#endif #endif
+105 -73
View File
@@ -44,7 +44,7 @@ struct WavReader
virtual ~WavReader() { } virtual ~WavReader() { }
virtual int Read( char *buf, unsigned len ) = 0; virtual int Read( char *buf, unsigned len ) = 0;
virtual int GetLength() const = 0; virtual int GetLength() const = 0;
virtual void Init() = 0; virtual bool Init() = 0;
virtual int SetPosition( int iMS ) = 0; virtual int SetPosition( int iMS ) = 0;
CString GetError() const { return m_sError; } CString GetError() const { return m_sError; }
@@ -59,12 +59,16 @@ struct WavReaderPCM: public WavReader
WavReaderPCM( RageFile &f, const RageSoundReader_WAV::WavData &data ): WavReaderPCM( RageFile &f, const RageSoundReader_WAV::WavData &data ):
WavReader(f, data) { } WavReader(f, data) { }
void Init() bool Init()
{ {
if( m_WavData.m_iBitsPerSample != 8 && m_WavData.m_iBitsPerSample != 16 ) 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 ); m_File.Seek( m_WavData.m_iDataChunkPos );
return true;
} }
int Read( char *buf, unsigned len ) int Read( char *buf, unsigned len )
@@ -132,27 +136,34 @@ public:
delete[] m_pBuffer; delete[] m_pBuffer;
} }
void Init() bool Init()
{ {
if( m_WavData.m_iBitsPerSample != 4 ) 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_File.Seek( m_WavData.m_iExtraFmtPos );
m_iFramesPerBlock = 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 ); int16_t iNumCoef = FileReading::read_16_le( m_File, m_sError );
m_iaCoef1.resize( iNumCoef ); m_iaCoef1.resize( iNumCoef );
m_iaCoef2.resize( iNumCoef ); m_iaCoef2.resize( iNumCoef );
for( int i = 0; i < iNumCoef; ++i ) for( int i = 0; i < iNumCoef; ++i )
{ {
m_iaCoef1[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_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_pBuffer = new int8_t[m_iFramesPerBlock*m_WavData.m_iChannels*sizeof(int16_t)];
m_iBufferAvail = m_iBufferUsed = 0; m_iBufferAvail = m_iBufferUsed = 0;
m_File.Seek( m_WavData.m_iDataChunkPos ); m_File.Seek( m_WavData.m_iDataChunkPos );
return true;
} }
void SetEOF() void SetEOF()
@@ -162,7 +173,7 @@ public:
} }
/* Return false on error, true on success (even if we hit EOF). */ /* 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) ); ASSERT_M( m_iBufferUsed == m_iBufferAvail, ssprintf("%i", m_iBufferUsed) );
@@ -171,25 +182,31 @@ public:
int8_t iPredictor[2]; int8_t iPredictor[2];
int16_t iDelta[2], iSamp1[2], iSamp2[2]; int16_t iDelta[2], iSamp1[2], iSamp2[2];
for( int i = 0; i < m_WavData.m_iChannels; ++i ) 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 ) 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 ) 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 ) 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() ) if( m_File.Tell() >= m_WavData.m_iDataChunkSize+m_WavData.m_iDataChunkPos || m_File.AtEOF() )
return; /* past the data chunk */ return true; /* past the data chunk */
CString sError;
int16_t *pBuffer = (int16_t *) m_pBuffer; int16_t *pBuffer = (int16_t *) m_pBuffer;
int iCoef1[2], iCoef2[2]; int iCoef1[2], iCoef2[2];
for( int i = 0; i < m_WavData.m_iChannels; ++i ) for( int i = 0; i < m_WavData.m_iChannels; ++i )
{ {
if( iPredictor[i] >= (int) m_iaCoef1.size() ) 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]]; iCoef1[i] = m_iaCoef1[iPredictor[i]];
iCoef2[i] = m_iaCoef2[iPredictor[i]]; iCoef2[i] = m_iaCoef2[iPredictor[i]];
@@ -203,7 +220,12 @@ public:
int iBlockSize = m_File.Read( pBuf, iMaxSize ); int iBlockSize = m_File.Read( pBuf, iMaxSize );
if( iBlockSize == 0 ) 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 ) for( int i = 0; i < m_WavData.m_iChannels; ++i )
pBuffer[m_iBufferAvail++] = iSamp2[i]; pBuffer[m_iBufferAvail++] = iSamp2[i];
@@ -254,6 +276,7 @@ public:
} }
m_iBufferAvail *= sizeof(int16_t); m_iBufferAvail *= sizeof(int16_t);
return true;
} }
int Read( char *buf, unsigned len ) int Read( char *buf, unsigned len )
@@ -263,12 +286,8 @@ public:
{ {
if( m_iBufferUsed == m_iBufferAvail ) if( m_iBufferUsed == m_iBufferAvail )
{ {
try { if( !DecodeADPCMBlock() )
DecodeADPCMBlock();
} catch( const FileReading::FatalError &err ) {
m_sError = err.what();
return -1; return -1;
}
} }
if( m_iBufferAvail == 0 ) if( m_iBufferAvail == 0 )
break; /* EOF */ break; /* EOF */
@@ -320,12 +339,8 @@ public:
m_File.Seek( iByte+m_WavData.m_iDataChunkPos ); m_File.Seek( iByte+m_WavData.m_iDataChunkPos );
} }
try { if( !DecodeADPCMBlock() )
DecodeADPCMBlock();
} catch( const FileReading::FatalError &err ) {
m_sError = err.what();
return -1; return -1;
}
const int iRemainingFrames = iFrame - iBlock*m_iFramesPerBlock; const int iRemainingFrames = iFrame - iBlock*m_iFramesPerBlock;
m_iBufferUsed = iRemainingFrames * m_WavData.m_iChannels * sizeof(int16_t); m_iBufferUsed = iRemainingFrames * m_WavData.m_iChannels * sizeof(int16_t);
@@ -338,34 +353,62 @@ public:
return iMS; 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; CString sBuf;
char *pBuf = sBuf.GetBuffer( iSize ); char *pBuf = sBuf.GetBuffer( iSize );
FileReading::ReadBytes( f, pBuf, iSize ); FileReading::ReadBytes( f, pBuf, iSize, sError );
sBuf.ReleaseBuffer( iSize ); sBuf.ReleaseBuffer( iSize );
return sBuf; 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: */ /* RIFF header: */
if( ReadString( m_File, 4 ) != "RIFF" ) if( ReadString( m_File, 4, sError ) != "RIFF" )
throw NotWAV(); {
FileReading::read_32_le( m_File ); /* file size */ SetError( "Not a WAV file" );
if( ReadString( m_File, 4 ) != "WAVE" ) return OPEN_UNKNOWN_FILE_FORMAT;
throw NotWAV(); }
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; int16_t iFormatTag = 0;
bool bGotFormatChunk = false, bGotDataChunk = false; bool bGotFormatChunk = false, bGotDataChunk = false;
while( !bGotFormatChunk || !bGotDataChunk ) 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; int iNextChunk = m_File.Tell() + iChunkSize;
/* Chunks are always word-aligned: */ /* Chunks are always word-aligned: */
@@ -376,19 +419,19 @@ void RageSoundReader_WAV::OpenInternal()
if( bGotFormatChunk ) if( bGotFormatChunk )
LOG->Warn( "File %s has more than one fmt chunk", m_File.GetPath().c_str() ); LOG->Warn( "File %s has more than one fmt chunk", m_File.GetPath().c_str() );
iFormatTag = FileReading::read_16_le( m_File ); iFormatTag = FileReading::read_16_le( m_File, sError );
m_WavData.m_iChannels = FileReading::read_16_le( m_File ); m_WavData.m_iChannels = FileReading::read_16_le( m_File, sError );
m_WavData.m_iSampleRate = FileReading::read_32_le( m_File ); m_WavData.m_iSampleRate = FileReading::read_32_le( m_File, sError );
FileReading::read_32_le( m_File ); /* BytesPerSec */ FileReading::read_32_le( m_File, sError ); /* BytesPerSec */
m_WavData.m_iBlockAlign = FileReading::read_16_le( m_File ); m_WavData.m_iBlockAlign = FileReading::read_16_le( m_File, sError );
m_WavData.m_iBitsPerSample = FileReading::read_16_le( m_File ); m_WavData.m_iBitsPerSample = FileReading::read_16_le( m_File, sError );
m_WavData.m_iExtraFmtBytes = FileReading::read_16_le( m_File ); m_WavData.m_iExtraFmtBytes = FileReading::read_16_le( m_File, sError );
if( m_WavData.m_iChannels < 1 || m_WavData.m_iChannels > 2 ) 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 */ 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(); m_WavData.m_iExtraFmtPos = m_File.Tell();
@@ -415,6 +458,12 @@ void RageSoundReader_WAV::OpenInternal()
m_File.Seek( iNextChunk ); m_File.Seek( iNextChunk );
} }
if( sError.size() != 0 )
{
SetError( sError );
return OPEN_FATAL_ERROR;
}
switch( iFormatTag ) switch( iFormatTag )
{ {
case 1: // PCM case 1: // PCM
@@ -425,31 +474,14 @@ void RageSoundReader_WAV::OpenInternal()
break; break;
case 85: // MP3 case 85: // MP3
/* Return unknown, so other decoders will be tried. MAD can read MP3s embedded in WAVs. */ /* 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; return OPEN_UNKNOWN_FILE_FORMAT;
} catch( const FileReading::FatalError &err ) { default:
SetError( err.what() ); FATAL_ERROR( ssprintf( "Unsupported data format %i", iFormatTag) );
}
if( !m_pImpl->Init() )
{
SetError( m_pImpl->GetError() );
return OPEN_FATAL_ERROR; return OPEN_FATAL_ERROR;
} }
-1
View File
@@ -37,7 +37,6 @@ private:
WavReader *m_pImpl; WavReader *m_pImpl;
void OpenInternal();
int SetPosition( int ms ); int SetPosition( int ms );
}; };
+70 -55
View File
@@ -16,56 +16,68 @@ enum
COMP_BI_BITFIELDS 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]; char magic[2];
ReadBytes( f, magic, 2 ); ReadBytes( f, magic, 2, sError );
if( magic[0] != 'B' || magic[1] != 'M' ) 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; uint32_t iWidth, iHeight, iPlanes, iBPP, iCompression = COMP_BI_RGB, iColors = 0;
if( iHeaderSize == 12 ) if( iHeaderSize == 12 )
{ {
/* OS/2 format */ /* OS/2 format */
iWidth = read_u16_le( f ); iWidth = read_u16_le( f, sError );
iHeight = read_u16_le( f ); iHeight = read_u16_le( f, sError );
iPlanes = read_u16_le( f ); iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f ); iBPP = read_u16_le( f, sError );
} }
else if( iHeaderSize == 40 ) else if( iHeaderSize == 40 )
{ {
iWidth = read_u32_le( f ); iWidth = read_u32_le( f, sError );
iHeight = read_u32_le( f ); iHeight = read_u32_le( f, sError );
iPlanes = read_u16_le( f ); iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f ); iBPP = read_u16_le( f, sError );
iCompression = read_u32_le( f ); iCompression = read_u32_le( f, sError );
read_u32_le( f ); /* bitmap size */ read_u32_le( f, sError ); /* bitmap size */
read_u32_le( f ); /* horiz resolution */ read_u32_le( f, sError ); /* horiz resolution */
read_u32_le( f ); /* vert resolution */ read_u32_le( f, sError ); /* vert resolution */
iColors = read_u32_le( f ); iColors = read_u32_le( f, sError );
read_u32_le( f ); /* "important" colors */ read_u32_le( f, sError ); /* "important" colors */
} }
else 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 ) if( iBPP <= 8 && iColors == 0 )
iColors = 1 << iBPP; iColors = 1 << iBPP;
if( iPlanes != 1 ) 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 ) 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 ) 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 ) 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; int iFileBPP = iBPP;
iBPP = max( iBPP, 8u ); iBPP = max( iBPP, 8u );
@@ -92,36 +104,43 @@ static RageSurface *LoadBMP( RageFile &f, RageSurface *&ret )
if( iCompression == COMP_BI_BITFIELDS ) if( iCompression == COMP_BI_BITFIELDS )
{ {
Rmask = read_u32_le( f ); Rmask = read_u32_le( f, sError );
Gmask = read_u32_le( f ); Gmask = read_u32_le( f, sError );
Bmask = read_u32_le( f ); 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 ) if( iBPP == 8 )
{ {
RageSurfaceColor Palette[256]; RageSurfaceColor Palette[256];
ZERO( Palette ); ZERO( Palette );
if( iColors > 256 ) if( iColors > 256 )
throw FatalError( ssprintf( "unexpected colors %i", iColors ) ); FATAL_ERROR( ssprintf( "unexpected colors %i", iColors ) );
for( unsigned i = 0; i < iColors; ++i ) for( unsigned i = 0; i < iColors; ++i )
{ {
Palette[i].b = read_8( f ); Palette[i].b = read_8( f, sError );
Palette[i].g = read_8( f ); Palette[i].g = read_8( f, sError );
Palette[i].r = read_8( f ); Palette[i].r = read_8( f, sError );
Palette[i].a = 0xFF; Palette[i].a = 0xFF;
/* Windows BMP palettes are padded to 32bpp. */ /* Windows BMP palettes are padded to 32bpp. */
if( iHeaderSize == 40 ) if( iHeaderSize == 40 )
read_8( f ); read_8( f, sError );
} }
memcpy( img->fmt.palette->colors, Palette, sizeof(Palette) ); 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 int iFilePitch = iFileBPP * iWidth; // in bits
iFilePitch = (iFilePitch+7) / 8; // in bytes: round up iFilePitch = (iFilePitch+7) / 8; // in bytes: round up
iFilePitch = (iFilePitch+3) & ~3; // round up a multiple of 4 iFilePitch = (iFilePitch+3) & ~3; // round up a multiple of 4
@@ -129,9 +148,9 @@ try { /* file reading may throw */
{ {
int ret = f.Seek( iDataOffset ); int ret = f.Seek( iDataOffset );
if( ret == -1 ) if( ret == -1 )
throw FatalError( f.GetError() ); FATAL_ERROR( f.GetError() );
if( ret != (int) iDataOffset ) if( ret != (int) iDataOffset )
throw UnexpectedEOF(); FATAL_ERROR( "Unexpected end of file" );
} }
for( int y = (int) iHeight-1; y >= 0; --y ) for( int y = (int) iHeight-1; y >= 0; --y )
@@ -165,15 +184,11 @@ try { /* file reading may throw */
else else
memcpy( pRow, buf.data(), img->pitch ); memcpy( pRow, buf.data(), img->pitch );
} }
} catch(...) {
delete img; return sError.size() != 0? RageSurfaceUtils::OPEN_FATAL_ERROR: RageSurfaceUtils::OPEN_OK;
throw;
} }
return img; RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const CString &sPath, RageSurface *&img, bool bHeaderOnly, CString &error )
}
RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const CString &sPath, RageSurface *&ret, bool bHeaderOnly, CString &error )
{ {
RageFile f; RageFile f;
@@ -183,17 +198,17 @@ RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const CString &sPath, RageSur
return RageSurfaceUtils::OPEN_FATAL_ERROR; return RageSurfaceUtils::OPEN_FATAL_ERROR;
} }
try { RageSurfaceUtils::OpenResult ret;
ret = LoadBMP( f, ret ); img = NULL;
} catch( const NotBMP & ) { ret = LoadBMP( f, img, error );
error = "not a BMP";
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; if( ret != RageSurfaceUtils::OPEN_OK && img != NULL )
} catch( const FatalError &err ) { {
error = err.what(); delete img;
return RageSurfaceUtils::OPEN_FATAL_ERROR; img = NULL;
} }
return RageSurfaceUtils::OPEN_OK; return ret;
} }
/* /*