start eliminating exception use; gcc apparently bloats exceptions to
a degree that makes them not worth it
This commit is contained in:
+32
-15
@@ -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 );
|
||||||
|
if( sError.size() == 0 )
|
||||||
return val;
|
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 );
|
||||||
|
if( sError.size() == 0 )
|
||||||
return Swap16LE( val );
|
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 );
|
||||||
|
if( sError.size() == 0 )
|
||||||
return Swap16LE( val );
|
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 );
|
||||||
|
if( sError.size() == 0 )
|
||||||
return Swap32LE( val );
|
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 );
|
||||||
|
if( sError.size() == 0 )
|
||||||
return Swap32LE( val );
|
return Swap32LE( val );
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,13 +286,9 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ private:
|
|||||||
|
|
||||||
WavReader *m_pImpl;
|
WavReader *m_pImpl;
|
||||||
|
|
||||||
void OpenInternal();
|
|
||||||
int SetPosition( int ms );
|
int SetPosition( int ms );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user