virtual wxColour GetTransparentColour(unsigned int frame) const;
// implementation of wxAnimationDecoder's pure virtuals
- virtual bool CanRead( wxInputStream& stream ) const;
+
virtual bool Load( wxInputStream& stream );
bool ConvertToImage(unsigned int frame, wxImage *image) const;
{ return wxANIMATION_TYPE_ANI; }
private:
+ // wxAnimationDecoder pure virtual:
+ virtual bool DoCanRead( wxInputStream& stream ) const;
+ // modifies current stream position (see wxAnimationDecoder::CanRead)
+
// frames stored as wxImage(s): ANI files are meant to be used mostly for animated
// cursors and thus they do not use any optimization to encode differences between
// two frames: they are just a list of images to display sequentially.
}
virtual bool Load( wxInputStream& stream ) = 0;
- virtual bool CanRead( wxInputStream& stream ) const = 0;
+
+ 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(_T("Failed to rewind the stream in wxAnimationDecoder!"));
+
+ // reading would fail anyhow as we're not at the right position
+ return false;
+ }
+
+ return ok;
+ }
virtual wxAnimationDecoder *Clone() const = 0;
virtual wxAnimationType GetType() const = 0;
unsigned int GetFrameCount() const { return m_nFrames; }
protected:
+ // checks the signature of the data in the given stream and returns true if it
+ // appears to be a valid animation format recognized by the animation decoder;
+ // this function should modify the stream current position without taking care
+ // of restoring it since CanRead() will do it.
+ virtual bool DoCanRead(wxInputStream& stream) const = 0;
+
wxSize m_szAnimation;
unsigned int m_nFrames;
void Destroy();
// implementation of wxAnimationDecoder's pure virtuals
- virtual bool CanRead( wxInputStream& stream ) const;
virtual bool Load( wxInputStream& stream )
{ return LoadGIF(stream) == wxGIF_OK; }
{ return wxANIMATION_TYPE_GIF; }
private:
+ // wxAnimationDecoder pure virtual
+ virtual bool DoCanRead( wxInputStream& stream ) const;
+ // modifies current stream position (see wxAnimationDecoder::CanRead)
+
+ int getcode(wxInputStream& stream, int bits, int abfin);
+ wxGIFErrorCode dgif(wxInputStream& stream,
+ GIFImage *img, int interl, int bits);
+
+
// array of all frames
wxArrayPtrVoid m_frames;
unsigned char m_buffer[256]; // buffer for reading
unsigned char *m_bufp; // pointer to next byte in buffer
- int getcode(wxInputStream& stream, int bits, int abfin);
- wxGIFErrorCode dgif(wxInputStream& stream,
- GIFImage *img, int interl, int bits);
-
wxDECLARE_NO_COPY_CLASS(wxGIFDecoder);
};
virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true );
virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 );
virtual bool DoLoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index );
- virtual int GetImageCount( wxInputStream& stream );
+
protected:
+ virtual int DoGetImageCount( wxInputStream& stream );
virtual bool DoCanRead( wxInputStream& stream );
#endif // wxUSE_STREAMS
#if wxUSE_STREAMS
virtual bool SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose=true) ){return false ;}
virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 );
- virtual int GetImageCount( wxInputStream& stream );
+
protected:
+ virtual int DoGetImageCount( wxInputStream& stream );
virtual bool DoCanRead( wxInputStream& stream );
#endif // wxUSE_STREAMS
{ }
#if wxUSE_STREAMS
- virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 );
- virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true );
-
- virtual int GetImageCount( wxInputStream& stream );
+ // NOTE: LoadFile and SaveFile are not pure virtuals to allow derived classes
+ // to implement only one of the two
+ virtual bool LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream),
+ bool WXUNUSED(verbose)=true, int WXUNUSED(index)=-1 )
+ { return false; }
+ virtual bool SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream),
+ bool WXUNUSED(verbose)=true )
+ { return false; }
+
+ int GetImageCount( wxInputStream& stream );
+ // save the stream position, call DoGetImageCount() and restore the position
bool CanRead( wxInputStream& stream ) { return CallDoCanRead(stream); }
bool CanRead( const wxString& name );
protected:
#if wxUSE_STREAMS
+ // NOTE: this function is allowed to change the current stream position
+ // since GetImageCount() will take care of restoring it later
+ virtual int DoGetImageCount( wxInputStream& WXUNUSED(stream) )
+ { return 1; } // default return value is 1 image
+
+ // NOTE: this function is allowed to change the current stream position
+ // since CallDoCanRead() will take care of restoring it later
virtual bool DoCanRead( wxInputStream& stream ) = 0;
// save the stream position, call DoCanRead() and restore the position
bool verbose = true, int index = -1);
virtual bool SaveFile(wxImage *image, wxOutputStream& stream,
bool verbose=true);
- virtual int GetImageCount(wxInputStream& stream);
+
protected:
+ virtual int DoGetImageCount(wxInputStream& stream);
virtual bool DoCanRead(wxInputStream& stream);
#endif // wxUSE_STREAMS
#if wxUSE_STREAMS
virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 );
virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true );
- virtual int GetImageCount( wxInputStream& stream );
+
protected:
+ virtual int DoGetImageCount( wxInputStream& stream );
virtual bool DoCanRead( wxInputStream& stream );
#endif
#if wxUSE_STREAMS
// Is the stream XPM file?
+ // NOTE: this function modifies the current stream position
bool CanRead(wxInputStream& stream);
+
// Read XPM file from the stream, parse it and create image from it
wxImage ReadFile(wxInputStream& stream);
#endif
+
// Read directly from XPM data (as passed to wxBitmap ctor):
wxImage ReadData(const char* const* xpm_data);
+
#ifdef __BORLANDC__
// needed for Borland 5.5
- wxImage ReadData(char** xpm_data) { return ReadData(const_cast<const char* const*>(xpm_data)); }
+ wxImage ReadData(char** xpm_data)
+ { return ReadData(const_cast<const char* const*>(xpm_data)); }
#endif
};
*/
virtual ~wxImageHandler();
+ /**
+ Returns @true if this handler supports the image format contained in the
+ given stream.
+
+ This function doesn't modify the current stream position (because it
+ restores the original position before returning; this however requires the
+ stream to be seekable; see wxStreamBase::IsSeekable).
+ */
+ bool CanRead( wxInputStream& stream );
+
+ /**
+ Returns @true if this handler supports the image format contained in the
+ file with the given name.
+
+ This function doesn't modify the current stream position (because it
+ restores the original position before returning; this however requires the
+ stream to be seekable; see wxStreamBase::IsSeekable).
+ */
+ bool CanRead( const wxString& filename );
+
/**
Gets the preferred file extension associated with this handler.
@param stream
Opened input stream for reading image data.
- Currently, the stream must support seeking.
+ This function doesn't modify the current stream position (because it
+ restores the original position before returning; this however requires the
+ stream to be seekable; see wxStreamBase::IsSeekable).
@return Number of available images. For most image handlers, this is 1
(exceptions are TIFF and ICO formats as well as animated GIFs
/**
- Returns @true if the current image handlers can read this file
+ Returns @true if at least one of the available image handlers can read
+ the file with the given name.
+
+ See wxImageHandler::CanRead for more info.
*/
static bool CanRead(const wxString& filename);
+
+ /**
+ Returns @true if at least one of the available image handlers can read
+ the data in the given stream.
+
+ See wxImageHandler::CanRead for more info.
+ */
+ static bool CanRead(wxInputStream& stream);
//@{
/**
For the overload taking the parameter @a filename, that's the name
of the file to query.
- For the overload taking the parameter @a stream, that's the ppened input
- stream with image data. Currently, the stream must support seeking.
+ For the overload taking the parameter @a stream, that's the opened input
+ stream with image data.
+
+ See wxImageHandler::GetImageCount() for more info.
The parameter @a type may be one of the following values:
@li wxBITMAP_TYPE_BMP: Load a Windows bitmap file.
virtual bool IsOk() const;
/**
- Returns @true if the streams supports seeking to arbitrary offsets.
+ Returns @true if the stream supports seeking to arbitrary offsets.
*/
virtual bool IsSeekable() const;
/**
Changes the stream current position.
+ This operation in general is possible only for seekable streams
+ (see wxStreamBase::IsSeekable()); non-seekable streams support only
+ seeking positive amounts in mode @c wxFromCurrent (this is implemented
+ by reading data and simply discarding it).
+
@param pos
Offset to seek to.
@param mode
virtual wxFileOffset SeekI(wxFileOffset pos, wxSeekMode mode = wxFromStart);
/**
- Returns the current stream position.
+ Returns the current stream position or ::wxInvalidOffset if it's not
+ available (e.g. socket streams do not have a size nor a current stream
+ position).
*/
virtual wxFileOffset TellI() 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 );
wxInt32 anih32;
memcpy( &anih32, "anih", 4 );
- if ( stream.SeekI(0) == wxInvalidOffset )
- return false;
if ( !stream.Read(&FCC1, 4) )
return false;
wxInt32 seq32;
memcpy( &seq32, "seq ", 4 );
- if ( stream.SeekI(0) == wxInvalidOffset)
- return false;
if ( !stream.Read(&FCC1, 4) )
return false;
if ( FCC1 != riff32 )
// 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;
}
*/
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
}
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);
}
#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]);
{
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?
bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream,
bool verbose, int index)
{
- if (stream.SeekI(0) == wxInvalidOffset)
- return false;
return DoLoadFile(image, stream, verbose, index);
}
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);
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 )
{
colmax = pCurrentEntry->bColorCount;
}
}
+
pCurrentEntry++;
}
{
// 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 )
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
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
{
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();
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 )
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
{
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();
}
// 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;
};
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);
}
wxIFFDecoder decod(&stream);
return decod.CanRead();
+ // it's ok to modify the stream position here
}
#endif // wxUSE_STREAMS
{
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;
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;
{
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;
{
Skip_Comment(stream);
+ // it's ok to modify the stream position here
if ( stream.GetC() == 'P' )
{
switch ( stream.GetC() )
{
// 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.
return true;
}
-int wxTIFFHandler::GetImageCount( wxInputStream& stream )
+int wxTIFFHandler::DoGetImageCount( wxInputStream& stream )
{
TIFF *tif = TIFFwxOpen( stream, "image", "r" );
} while (TIFFReadDirectory(tif));
TIFFClose( tif );
+
+ // NOTE: this function modifies the current stream position but it's ok
+ // (see wxImageHandler::GetImageCount)
return dircount;
}
{
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') ||
{
wxXPMDecoder decoder;
return decoder.CanRead(stream);
+ // it's ok to modify the stream position here
}
#endif // wxUSE_STREAMS
{
// 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
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;
}