document that CanRead() and GetImageCount() functions of wxImageHandlers do NOT modify the current stream position and that they require seekable streams; rename current GetImageCount() functions to DoGetImageCount() and put save-and-restore stream position logic in GetImageCount(); add comments in the various DoCanRead() and in DoGetImageCount() where the stream position is modified; remove unneeded SeekI(0) calls from DoCanRead() and DoGetImageCount() functions: they didn't allow to load images from non-seekable streams; implement forward-seeking in wxInputStream::SeekI() also for non-seekable streams

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@60852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2009-06-01 11:43:36 +00:00
parent 1f51673bb8
commit 8faef7ccbc
25 changed files with 236 additions and 93 deletions

View File

@@ -113,10 +113,10 @@ wxColour wxANIDecoder::GetTransparentColour(unsigned int frame) const
// ANI reading and decoding
//---------------------------------------------------------------------------
bool wxANIDecoder::CanRead(wxInputStream& stream) const
bool wxANIDecoder::DoCanRead(wxInputStream& stream) const
{
wxInt32 FCC1, FCC2;
wxUint32 datalen ;
wxUint32 datalen;
wxInt32 riff32;
memcpy( &riff32, "RIFF", 4 );
@@ -127,8 +127,6 @@ bool wxANIDecoder::CanRead(wxInputStream& stream) const
wxInt32 anih32;
memcpy( &anih32, "anih", 4 );
if ( stream.SeekI(0) == wxInvalidOffset )
return false;
if ( !stream.Read(&FCC1, 4) )
return false;
@@ -222,8 +220,6 @@ bool wxANIDecoder::Load( wxInputStream& stream )
wxInt32 seq32;
memcpy( &seq32, "seq ", 4 );
if ( stream.SeekI(0) == wxInvalidOffset)
return false;
if ( !stream.Read(&FCC1, 4) )
return false;
if ( FCC1 != riff32 )

View File

@@ -575,16 +575,13 @@ as an End of Information itself)
// CanRead:
// Returns true if the file looks like a valid GIF, false otherwise.
//
bool wxGIFDecoder::CanRead(wxInputStream &stream) const
bool wxGIFDecoder::DoCanRead(wxInputStream &stream) const
{
unsigned char buf[3];
if ( !stream.Read(buf, WXSIZEOF(buf)) )
return false;
if (stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent) == wxInvalidOffset)
return false; // this happens e.g. for non-seekable streams
return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0;
}

View File

@@ -641,7 +641,9 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
*/
if ( IsBmp )
{
if (stream.SeekI(bmpOffset) == wxInvalidOffset)
// NOTE: seeking a positive amount in wxFromCurrent mode allows us to
// load even non-seekable streams (see wxInputStream::SeekI docs)!
if (stream.SeekI(bmpOffset, wxFromCurrent) == wxInvalidOffset)
return false;
//else: icon, just carry on
}
@@ -899,15 +901,9 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream,
wxInt32 dbuf[4];
wxInt8 bbuf[4];
wxFileOffset offset = 0; // keep gcc quiet
if ( IsBmp )
{
// read the header off the .BMP format file
offset = stream.TellI();
if (offset == wxInvalidOffset)
offset = 0;
stream.Read(bbuf, 2);
stream.Read(dbuf, 16);
}
@@ -918,7 +914,7 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream,
#if 0 // unused
wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]);
#endif
offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]);
wxFileOffset offset = wxINT32_SWAP_ON_BE(dbuf[2]);
stream.Read(dbuf, 4 * 2);
int width = wxINT32_SWAP_ON_BE((int)dbuf[0]);
@@ -1021,7 +1017,7 @@ bool wxBMPHandler::DoCanRead(wxInputStream& stream)
{
unsigned char hdr[2];
if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
return false;
// do we have the BMP file signature?
@@ -1259,8 +1255,6 @@ bool wxICOHandler::SaveFile(wxImage *image,
bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream,
bool verbose, int index)
{
if (stream.SeekI(0) == wxInvalidOffset)
return false;
return DoLoadFile(image, stream, verbose, index);
}
@@ -1272,9 +1266,9 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
ICONDIR IconDir;
wxFileOffset iPos = stream.TellI();
stream.Read(&IconDir, sizeof(IconDir));
wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
// nType is 1 for Icons, 2 for Cursors:
wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType);
@@ -1285,9 +1279,13 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
int colmax = 0;
int iSel = wxNOT_FOUND;
for (int i = 0; i < nIcons; i++ )
// remember how many bytes we read from the stream:
wxFileOffset offset = sizeof(IconDir);
for (unsigned int i = 0; i < nIcons; i++ )
{
stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY));
offset += stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY)).LastRead();
// bHeight and bColorCount are wxUint8
if ( pCurrentEntry->bWidth >= wMax )
{
@@ -1301,6 +1299,7 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
colmax = pCurrentEntry->bColorCount;
}
}
pCurrentEntry++;
}
@@ -1320,8 +1319,13 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
{
// seek to selected icon:
pCurrentEntry = pIconDirEntry + iSel;
if (stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart) == wxInvalidOffset)
// NOTE: seeking a positive amount in wxFromCurrent mode allows us to
// load even non-seekable streams (see wxInputStream::SeekI docs)!
if (stream.SeekI(wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset) - offset,
wxFromCurrent) == wxInvalidOffset)
return false;
bResult = LoadDib(image, stream, true, IsBmp);
bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI);
if ( bResult && bIsCursorType && nType == 2 )
@@ -1331,30 +1335,27 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream,
image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount));
}
}
delete[] pIconDirEntry;
delete [] pIconDirEntry;
return bResult;
}
int wxICOHandler::GetImageCount(wxInputStream& stream)
int wxICOHandler::DoGetImageCount(wxInputStream& stream)
{
ICONDIR IconDir;
wxFileOffset iPos = stream.TellI();
if (stream.SeekI(0) == wxInvalidOffset)
return 0;
if (stream.Read(&IconDir, sizeof(IconDir)).LastRead() != sizeof(IconDir))
// it's ok to modify the stream position here
return 0;
wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount);
if (stream.SeekI(iPos) == wxInvalidOffset)
return 0;
return (int)nIcons;
return (int)wxUINT16_SWAP_ON_BE(IconDir.idCount);
}
bool wxICOHandler::DoCanRead(wxInputStream& stream)
{
if (stream.SeekI(0) == wxInvalidOffset)
return false;
unsigned char hdr[4];
if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
return false;
// hdr[2] is one for an icon and two for a cursor
@@ -1374,10 +1375,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler)
bool wxCURHandler::DoCanRead(wxInputStream& stream)
{
if (stream.SeekI(0) == wxInvalidOffset)
return false;
unsigned char hdr[4];
if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
return false;
// hdr[2] is one for an icon and two for a cursor
@@ -1408,12 +1407,13 @@ bool wxANIHandler::DoCanRead(wxInputStream& stream)
{
wxANIDecoder decod;
return decod.CanRead(stream);
// it's ok to modify the stream position here
}
int wxANIHandler::GetImageCount(wxInputStream& stream)
int wxANIHandler::DoGetImageCount(wxInputStream& stream)
{
wxANIDecoder decoder;
if (!decoder.Load(stream))
if (!decoder.Load(stream)) // it's ok to modify the stream position here
return wxNOT_FOUND;
return decoder.GetFrameCount();

View File

@@ -2658,19 +2658,27 @@ void wxImage::RotateHue(double angle)
IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
#if wxUSE_STREAMS
bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
int wxImageHandler::GetImageCount( wxInputStream& stream )
{
return false;
}
// NOTE: this code is the same of wxAnimationDecoder::CanRead and
// wxImageHandler::CallDoCanRead
bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
{
return false;
}
if ( !stream.IsSeekable() )
return false; // can't test unseekable stream
int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
{
return 1;
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(_T("Failed to rewind the stream in wxImageHandler!"));
// reading would fail anyhow as we're not at the right position
return false;
}
return n;
}
bool wxImageHandler::CanRead( const wxString& name )
@@ -2688,13 +2696,13 @@ bool wxImageHandler::CanRead( const wxString& name )
bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
{
wxFileOffset posOld = stream.TellI();
if ( posOld == wxInvalidOffset )
{
// can't test unseekable stream
return false;
}
// 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

View File

@@ -98,14 +98,18 @@ bool wxGIFHandler::DoCanRead( wxInputStream& stream )
{
wxGIFDecoder decod;
return decod.CanRead(stream);
// it's ok to modify the stream position here
}
int wxGIFHandler::GetImageCount( wxInputStream& stream )
int wxGIFHandler::DoGetImageCount( wxInputStream& stream )
{
wxGIFDecoder decod;
wxGIFErrorCode error = decod.LoadGIF(stream);
if ( (error != wxGIF_OK) && (error != wxGIF_TRUNCATED) )
return -1;
// NOTE: this function modifies the current stream position but it's ok
// (see wxImageHandler::GetImageCount)
return decod.GetFrameCount();
}

View File

@@ -98,7 +98,10 @@ public:
// constructor, destructor, etc.
wxIFFDecoder(wxInputStream *s);
~wxIFFDecoder() { Destroy(); }
// NOTE: this function modifies the current stream position
bool CanRead();
int ReadIFF();
bool ConvertToImage(wxImage *image) const;
};
@@ -234,9 +237,6 @@ bool wxIFFDecoder::CanRead()
if ( !m_f->Read(buf, WXSIZEOF(buf)) )
return false;
if ( m_f->SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent) == wxInvalidOffset )
return false;
return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0);
}
@@ -787,6 +787,7 @@ bool wxIFFHandler::DoCanRead(wxInputStream& stream)
wxIFFDecoder decod(&stream);
return decod.CanRead();
// it's ok to modify the stream position here
}
#endif // wxUSE_STREAMS

View File

@@ -479,7 +479,7 @@ bool wxJPEGHandler::DoCanRead( wxInputStream& stream )
{
unsigned char hdr[2];
if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
return false;
return hdr[0] == 0xFF && hdr[1] == 0xD8;

View File

@@ -487,7 +487,7 @@ bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
bool wxPCXHandler::DoCanRead( wxInputStream& stream )
{
unsigned char c = stream.GetC();
unsigned char c = stream.GetC(); // it's ok to modify the stream position here
if ( !stream )
return false;

View File

@@ -302,7 +302,7 @@ bool wxPNGHandler::DoCanRead( wxInputStream& stream )
{
unsigned char hdr[4];
if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
return false;
return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0;

View File

@@ -180,6 +180,7 @@ bool wxPNMHandler::DoCanRead( wxInputStream& stream )
{
Skip_Comment(stream);
// it's ok to modify the stream position here
if ( stream.GetC() == 'P' )
{
switch ( stream.GetC() )

View File

@@ -741,7 +741,7 @@ bool wxTGAHandler::DoCanRead(wxInputStream& stream)
{
// read the fixed-size TGA headers
unsigned char hdr[HDR_SIZE];
stream.Read(hdr, HDR_SIZE);
stream.Read(hdr, HDR_SIZE); // it's ok to modify the stream position here
// Check wether we can read the file or not.

View File

@@ -413,7 +413,7 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos
return true;
}
int wxTIFFHandler::GetImageCount( wxInputStream& stream )
int wxTIFFHandler::DoGetImageCount( wxInputStream& stream )
{
TIFF *tif = TIFFwxOpen( stream, "image", "r" );
@@ -426,6 +426,9 @@ int wxTIFFHandler::GetImageCount( wxInputStream& stream )
} while (TIFFReadDirectory(tif));
TIFFClose( tif );
// NOTE: this function modifies the current stream position but it's ok
// (see wxImageHandler::GetImageCount)
return dircount;
}
@@ -587,7 +590,7 @@ bool wxTIFFHandler::DoCanRead( wxInputStream& stream )
{
unsigned char hdr[2];
if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) )
if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
return false;
return (hdr[0] == 'I' && hdr[1] == 'I') ||

View File

@@ -218,6 +218,7 @@ bool wxXPMHandler::DoCanRead(wxInputStream& stream)
{
wxXPMDecoder decoder;
return decoder.CanRead(stream);
// it's ok to modify the stream position here
}
#endif // wxUSE_STREAMS

View File

@@ -916,13 +916,48 @@ wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
{
// RR: This code is duplicated in wxBufferedInputStream. This is
// not really a good design, but buffered stream are different
// from all other in that they handle two stream-related objects,
// from all others in that they handle two stream-related objects:
// the stream buffer and parent stream.
// I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
if (m_lasterror==wxSTREAM_EOF)
m_lasterror=wxSTREAM_NO_ERROR;
// avoid unnecessary seek operations (optimization)
wxFileOffset currentPos = TellI(), size = GetLength();
if ((mode == wxFromStart && currentPos == pos) ||
(mode == wxFromCurrent && pos == 0) ||
(mode == wxFromEnd && size != wxInvalidOffset && currentPos == size-pos))
return currentPos;
if (!IsSeekable() && mode == wxFromCurrent && pos > 0)
{
// rather than seeking, we can just read data and discard it;
// this allows to forward-seek also non-seekable streams!
char buf[BUF_TEMP_SIZE];
size_t bytes_read;
// read chunks of BUF_TEMP_SIZE bytes until we reach the new position
for ( ; pos >= BUF_TEMP_SIZE; pos -= bytes_read)
{
bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
if ( m_lasterror != wxSTREAM_NO_ERROR )
return wxInvalidOffset;
wxASSERT(bytes_read == WXSIZEOF(buf));
}
// read the last 'pos' bytes
bytes_read = Read(buf, (size_t)pos).LastRead();
if ( m_lasterror != wxSTREAM_NO_ERROR )
return wxInvalidOffset;
wxASSERT(bytes_read == (size_t)pos);
// we should now have seeked to the right position...
return TellI();
}
/* RR: A call to SeekI() will automatically invalidate any previous
call to Ungetch(), otherwise it would be possible to SeekI() to
one position, unread some bytes there, SeekI() to another position

View File

@@ -122,9 +122,6 @@ bool wxXPMDecoder::CanRead(wxInputStream& stream)
if ( !stream.Read(buf, WXSIZEOF(buf)) )
return false;
if (stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent) == wxInvalidOffset)
return false;
return memcmp(buf, "/* XPM */", WXSIZEOF(buf)) == 0;
}