Factor out 3 copies of identical code into wxInputStreamPeeker

Resolve the long standing "NOTE" comments about having the same code in
wxAnimationDecoder::CanRead(), wxImage::CanRead() and GetImageCount() by
extracting the common logic into a helper wxInputStreamPeeker class and
using it from all places.

This loses the possibility to log a debug message if rewinding the
stream fails, but this is probably not very valuable and the actual
error should be already logged by SeekI() itself when it fails on a
seekable stream.

No real changes.
This commit is contained in:
Vadim Zeitlin
2021-12-15 16:31:16 +01:00
parent b9a1931394
commit 28c3605f6b
3 changed files with 53 additions and 56 deletions

View File

@@ -96,24 +96,8 @@ public:
bool CanRead( wxInputStream& stream ) const
{
// NOTE: this code is the same of wxImageHandler::CallDoCanRead
if ( !stream.IsSeekable() )
return false; // can't test unseekable stream
wxFileOffset posOld = stream.TellI();
bool ok = DoCanRead(stream);
// restore the old position to be able to test other formats and so on
if ( stream.SeekI(posOld) == wxInvalidOffset )
{
wxLogDebug(wxT("Failed to rewind the stream in wxAnimationDecoder!"));
// reading would fail anyhow as we're not at the right position
return false;
}
return ok;
return wxInputStreamPeeker(stream).
CallIfCanSeek(&wxAnimationDecoder::DoCanRead, this);
}
virtual wxAnimationDecoder *Clone() const = 0;

View File

@@ -682,6 +682,53 @@ protected:
wxDECLARE_NO_COPY_CLASS(wxWrapperInputStream);
};
// ----------------------------------------------------------------------------
// wxPeekInputStream(): read some data from a stream and then rewind it back
// ----------------------------------------------------------------------------
// This semi-private class is used in wx code to read some data, using the
// provided method of the class T, from a stream if it's seekable and then
// rewind it back.
class wxInputStreamPeeker
{
public:
explicit wxInputStreamPeeker(wxInputStream& stream)
: m_stream(stream),
m_ofsOrig(stream.IsSeekable() ? stream.TellI() : wxInvalidOffset)
{
}
// Call the given function if the stream is seekable, otherwise return 0.
template <typename R, typename T>
R CallIfCanSeek(R (T::*func)(wxInputStream&), T* obj)
{
return RewindAndReturn(CanSeek() ? (obj->*func)(m_stream) : R(0));
}
// Overload for const methods.
template <typename R, typename T>
R CallIfCanSeek(R (T::*func)(wxInputStream&) const, const T* obj)
{
return RewindAndReturn(CanSeek() ? (obj->*func)(m_stream) : R(0));
}
private:
bool CanSeek() const { return m_ofsOrig != wxInvalidOffset; }
template <typename R>
R RewindAndReturn(R retval)
{
if ( CanSeek() && m_stream.SeekI(m_ofsOrig) == wxInvalidOffset )
return R(0);
return retval;
}
wxInputStream& m_stream;
const wxFileOffset m_ofsOrig;
wxDECLARE_NO_COPY_CLASS(wxInputStreamPeeker);
};
#endif // wxUSE_STREAMS

View File

@@ -3445,25 +3445,8 @@ wxIMPLEMENT_ABSTRACT_CLASS(wxImageHandler, wxObject);
#if wxUSE_STREAMS
int wxImageHandler::GetImageCount( wxInputStream& stream )
{
// NOTE: this code is the same of wxAnimationDecoder::CanRead and
// wxImageHandler::CallDoCanRead
if ( !stream.IsSeekable() )
return false; // can't test unseekable stream
wxFileOffset posOld = stream.TellI();
int n = DoGetImageCount(stream);
// restore the old position to be able to test other formats and so on
if ( stream.SeekI(posOld) == wxInvalidOffset )
{
wxLogDebug(wxT("Failed to rewind the stream in wxImageHandler!"));
// reading would fail anyhow as we're not at the right position
return false;
}
return n;
return wxInputStreamPeeker(stream).
CallIfCanSeek(&wxImageHandler::DoGetImageCount, this);
}
bool wxImageHandler::CanRead( const wxString& name )
@@ -3481,25 +3464,8 @@ bool wxImageHandler::CanRead( const wxString& name )
bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
{
// NOTE: this code is the same of wxAnimationDecoder::CanRead and
// wxImageHandler::GetImageCount
if ( !stream.IsSeekable() )
return false; // can't test unseekable stream
wxFileOffset posOld = stream.TellI();
bool ok = DoCanRead(stream);
// restore the old position to be able to test other formats and so on
if ( stream.SeekI(posOld) == wxInvalidOffset )
{
wxLogDebug(wxT("Failed to rewind the stream in wxImageHandler!"));
// reading would fail anyhow as we're not at the right position
return false;
}
return ok;
return wxInputStreamPeeker(stream)
.CallIfCanSeek(&wxImageHandler::DoCanRead, this);
}
#endif // wxUSE_STREAMS