diff --git a/include/wx/animdecod.h b/include/wx/animdecod.h index b5a0326aff..fa91508a32 100644 --- a/include/wx/animdecod.h +++ b/include/wx/animdecod.h @@ -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; diff --git a/include/wx/stream.h b/include/wx/stream.h index 496494f3e8..4de1d5b01b 100644 --- a/include/wx/stream.h +++ b/include/wx/stream.h @@ -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 + R CallIfCanSeek(R (T::*func)(wxInputStream&), T* obj) + { + return RewindAndReturn(CanSeek() ? (obj->*func)(m_stream) : R(0)); + } + + // Overload for const methods. + template + 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 + 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 diff --git a/src/common/image.cpp b/src/common/image.cpp index 9bb7ca2461..e79e270377 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -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