start eliminating exception use; gcc apparently bloats exceptions to
a degree that makes them not worth it
This commit is contained in:
+37
-20
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ private:
|
||||
|
||||
WavReader *m_pImpl;
|
||||
|
||||
void OpenInternal();
|
||||
int SetPosition( int ms );
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user