// Created: 11/07/98
// RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux
-// Licence: wxWindows license
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// headers
// ----------------------------------------------------------------------------
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "stream.h"
#endif
// ----------------------------------------------------------------------------
// the temporary buffer size used when copying from stream to stream
-#define BUF_TEMP_SIZE 10000
+#define BUF_TEMP_SIZE 4096
// ============================================================================
// implementation
void wxStreamBuffer::SetError(wxStreamError err)
{
- if ( m_stream->m_lasterror == wxStream_NOERROR )
+ if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR )
m_stream->m_lasterror = err;
}
m_fixed = TRUE;
}
-wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
+wxStreamBuffer::wxStreamBuffer(BufMode mode)
{
Init();
- m_stream = &stream;
+ m_stream = NULL;
m_mode = mode;
- m_flushable = TRUE;
- m_destroystream = FALSE;
+ m_flushable = FALSE;
}
-wxStreamBuffer::wxStreamBuffer(BufMode mode)
+wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
{
Init();
- wxASSERT_MSG(mode != read_write, wxT("you have to use the other ctor for read_write mode") );
- if ( mode == read )
- m_stream = new wxInputStream;
- else if ( mode == write)
- m_stream = new wxOutputStream;
- else
- m_stream = NULL;
-
+ m_stream = &stream;
m_mode = mode;
- m_flushable = FALSE;
- m_destroystream = TRUE;
+ m_flushable = TRUE;
}
wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
{
- // doing this has big chances to lead to a crashwhen the source buffer is
+ // doing this has big chances to lead to a crash when the source buffer is
// destroyed (otherwise assume the caller knows what he does)
- wxASSERT_MSG( !buffer.m_destroybuf && !buffer.m_destroystream,
+ wxASSERT_MSG( !buffer.m_destroybuf,
_T("it's a bad idea to copy this buffer") );
m_buffer_start = buffer.m_buffer_start;
m_stream = buffer.m_stream;
m_mode = buffer.m_mode;
m_destroybuf = FALSE;
- m_destroystream = FALSE;
}
void wxStreamBuffer::FreeBuffer()
wxStreamBuffer::~wxStreamBuffer()
{
FreeBuffer();
-
- if ( m_destroystream )
- delete m_stream;
}
wxInputStream *wxStreamBuffer::GetInputStream() const
void wxStreamBuffer::ResetBuffer()
{
- wxCHECK_RET( m_stream, _T("should have a stream in wxStreamBuffer") );
+ if ( m_stream )
+ {
+ m_stream->Reset();
+ m_stream->m_lastcount = 0;
+ }
- m_stream->m_lasterror = wxStream_NOERROR;
- m_stream->m_lastcount = 0;
- if (m_mode == read && m_flushable)
- m_buffer_pos = m_buffer_end;
- else
- m_buffer_pos = m_buffer_start;
+ m_buffer_pos = m_mode == read && m_flushable
+ ? m_buffer_end
+ : m_buffer_start;
}
// fill the buffer with as much data as possible (only for read buffers)
{
wxInputStream *inStream = GetInputStream();
- wxCHECK_MSG( inStream, FALSE, _T("should have a stream in wxStreamBuffer") );
+ // It's legal to have no stream, so we don't complain about it just return FALSE
+ if ( !inStream )
+ return FALSE;
size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
if ( !count )
void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
{
size_t left = GetBytesLeft();
+
if ( size > left )
{
if ( m_fixed )
// if we don't have buffer at all, just forward this call to the stream,
if ( !HasBuffer() )
{
- outStream->OnSysWrite(&c, 1);
+ outStream->OnSysWrite(&c, sizeof(c));
}
else
{
if ( !GetDataLeft() && !FlushBuffer() )
{
// we don't
- SetError(wxStream_WRITE_ERR);
+ SetError(wxSTREAM_WRITE_ERROR);
}
else
{
- PutToBuffer(&c, 1);
+ PutToBuffer(&c, sizeof(c));
m_stream->m_lastcount = 1;
}
}
if ( !GetDataLeft() )
{
- SetError(wxStream_READ_ERR);
+ SetError(wxSTREAM_READ_ERROR);
return 0;
}
char c;
- GetFromBuffer(&c, 1);
+ GetFromBuffer(&c, sizeof(c));
m_buffer_pos--;
return c;
char c;
if ( !HasBuffer() )
{
- inStream->OnSysRead(&c, 1);
+ inStream->OnSysRead(&c, sizeof(c));
}
else
{
if ( !GetDataLeft() )
{
- SetError(wxStream_READ_ERR);
+ SetError(wxSTREAM_READ_ERROR);
c = 0;
}
else
{
- GetFromBuffer(&c, 1);
+ GetFromBuffer(&c, sizeof(c));
m_stream->m_lastcount = 1;
}
}
size_t wxStreamBuffer::Read(void *buffer, size_t size)
{
- wxInputStream *inStream = GetInputStream();
-
- wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
-
// lasterror is reset before all new IO calls
- m_stream->m_lasterror = wxStream_NOERROR;
+ if ( m_stream )
+ m_stream->Reset();
+ size_t read;
if ( !HasBuffer() )
{
- m_stream->m_lastcount = inStream->OnSysRead(buffer, size);
+ wxInputStream *inStream = GetInputStream();
+
+ wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
+
+ read = inStream->OnSysRead(buffer, size);
}
else // we have a buffer, use it
{
if ( !FillBuffer() )
{
- SetError(wxStream_EOF);
+ SetError(wxSTREAM_EOF);
break;
}
}
}
}
- m_stream->m_lastcount = orig_size - size;
+ read = orig_size - size;
}
- return m_stream->m_lastcount;
+ if ( m_stream )
+ m_stream->m_lastcount = read;
+
+ return read;
}
// this should really be called "Copy()"
size_t wxStreamBuffer::Write(const void *buffer, size_t size)
{
- wxOutputStream *outStream = GetOutputStream();
+ if (m_stream)
+ {
+ // lasterror is reset before all new IO calls
+ m_stream->Reset();
+ }
- wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
-
- // lasterror is reset before all new IO calls
- m_stream->m_lasterror = wxStream_NOERROR;
+ size_t ret;
if ( !HasBuffer() && m_fixed )
{
+ wxOutputStream *outStream = GetOutputStream();
+
+ wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
+
// no buffer, just forward the call to the stream
- m_stream->m_lastcount = outStream->OnSysWrite(buffer, size);
+ ret = outStream->OnSysWrite(buffer, size);
}
else // we [may] have a buffer, use it
{
//
// FIXME: fine, but if it fails we should (re)try writing it by
// chunks as this will (hopefully) always work (VZ)
+
if ( size > left && m_fixed )
{
PutToBuffer(buffer, left);
if ( !FlushBuffer() )
{
- SetError(wxStream_WRITE_ERR);
+ SetError(wxSTREAM_WRITE_ERROR);
break;
}
}
}
- m_stream->m_lastcount = orig_size - size;
+ ret = orig_size - size;
+ }
+
+ if (m_stream)
+ {
+ // i am not entirely sure what we do this for
+ m_stream->m_lastcount = ret;
}
- return m_stream->m_lastcount;
+ return ret;
}
size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
off_t wxStreamBuffer::Tell() const
{
- off_t pos = m_stream->OnSysTell();
- if ( pos == wxInvalidOffset )
- return wxInvalidOffset;
+ off_t pos;
+
+ // ask the stream for position if we have a real one
+ if ( m_stream )
+ {
+ pos = m_stream->OnSysTell();
+ if ( pos == wxInvalidOffset )
+ return wxInvalidOffset;
+ }
+ else // no associated stream
+ {
+ pos = 0;
+ }
pos += GetIntPosition();
wxStreamBase::wxStreamBase()
{
- m_lasterror = wxStream_NOERROR;
+ m_lasterror = wxSTREAM_NO_ERROR;
m_lastcount = 0;
}
free(m_wback);
}
-size_t wxInputStream::OnSysRead(void * WXUNUSED(buffer),
- size_t WXUNUSED(bufsize))
+bool wxInputStream::CanRead() const
{
- return 0;
+ // we don't know if there is anything to read or not and by default we
+ // prefer to be optimistic and try to read data unless we know for sure
+ // there is no more of it
+ return m_lasterror != wxSTREAM_EOF;
}
bool wxInputStream::Eof() const
{
- wxInputStream *self = wxConstCast(this, wxInputStream);
-
- char c;
- self->Read(&c, 1);
-
- // some streams can know that they're at EOF before actually trying to
- // read beyond the end of stream (e.g. files) while others have no way of
- // knowing it, so to provide the same behaviour in all cases we only
- // return TRUE from here if the character really couldn't be read
- if ( !self->LastRead() && GetLastError() == wxSTREAM_EOF )
- {
- return TRUE;
- }
-
- self->Ungetch(c);
-
- return FALSE;
+ // the only way the base class can know we're at EOF is when we'd already
+ // tried to read beyond it in which case last error is set accordingly
+ return GetLastError() == wxSTREAM_EOF;
}
char *wxInputStream::AllocSpaceWBack(size_t needed_size)
return m_wback;
}
-size_t wxInputStream::GetWBack(void *buf, size_t bsize)
+size_t wxInputStream::GetWBack(void *buf, size_t size)
{
if (!m_wback)
return 0;
// how many bytes do we have in the buffer?
size_t toget = m_wbacksize - m_wbackcur;
- if ( bsize < toget )
+ if ( size < toget )
{
// we won't read everything
- toget = bsize;
+ toget = size;
}
- // copy the data from the cache
+ // copy the data from the cache
memcpy(buf, m_wback + m_wbackcur, toget);
m_wbackcur += toget;
size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
{
+ if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
+ {
+ // can't operate on this stream until the error is cleared
+ return 0;
+ }
+
char *ptrback = AllocSpaceWBack(bufsize);
if (!ptrback)
return 0;
+ // Eof() shouldn't return TRUE any longer
+ if ( m_lasterror == wxSTREAM_EOF )
+ m_lasterror = wxSTREAM_NO_ERROR;
+
memcpy(ptrback, buf, bufsize);
return bufsize;
}
bool wxInputStream::Ungetch(char c)
{
- void *ptrback = AllocSpaceWBack(1);
- if (!ptrback)
- return FALSE;
-
- *(char *)ptrback = c;
- return TRUE;
+ return Ungetch(&c, sizeof(c)) != 0;
}
char wxInputStream::GetC()
{
char c;
- Read(&c, 1);
+ Read(&c, sizeof(c));
return c;
}
wxInputStream& wxInputStream::Read(void *buf, size_t size)
{
- size_t retsize = GetWBack(buf, size);
- if (retsize == size)
+ char *p = (char *)buf;
+ m_lastcount = 0;
+
+ size_t read = GetWBack(buf, size);
+ for ( ;; )
{
- m_lastcount = size;
- m_lasterror = wxStream_NOERROR;
- return *this;
+ size -= read;
+ m_lastcount += read;
+ p += read;
+
+ if ( !size )
+ {
+ // we read the requested amount of data
+ break;
+ }
+
+ if ( p != buf && !CanRead() )
+ {
+ // we have already read something and we would block in OnSysRead()
+ // now: don't do it but return immediately
+ break;
+ }
+
+ read = OnSysRead(p, size);
+ if ( !read )
+ {
+ // no more data available
+ break;
+ }
}
- size -= retsize;
- buf = (char *)buf + retsize;
- m_lastcount = OnSysRead(buf, size) + retsize;
return *this;
}
char wxInputStream::Peek()
{
char c;
- Read(&c, 1);
- if (m_lasterror == wxStream_NOERROR)
+ Read(&c, sizeof(c));
+ if (m_lasterror == wxSTREAM_NO_ERROR)
{
Ungetch(c);
return c;
wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
{
char buf[BUF_TEMP_SIZE];
- size_t bytes_read = BUF_TEMP_SIZE;
- while (bytes_read == BUF_TEMP_SIZE)
+ for ( ;; )
{
- bytes_read = Read(buf, bytes_read).LastRead();
- bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
+ size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
+ if ( !bytes_read )
+ break;
+
+ if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
+ break;
}
+
return *this;
}
// I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
if (m_lasterror==wxSTREAM_EOF)
- m_lasterror=wxSTREAM_NOERROR;
+ m_lasterror=wxSTREAM_NO_ERROR;
/* RR: A call to SeekI() will automatically invalidate any previous
call to Ungetch(), otherwise it would be possible to SeekI() to
buffer if possible, but is it really needed? It would only work
when seeking in wxFromCurrent mode, else it would invalidate
anyway... */
-
+
if (m_wback)
{
wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
-
+
free(m_wback);
m_wback = NULL;
m_wbacksize = 0;
void wxOutputStream::PutC(char c)
{
- Write(&c, 1);
+ Write(&c, sizeof(c));
}
wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
{
// reset the error flag
- m_lasterror = wxStream_NOERROR;
+ Reset();
// first read from the already cached data
m_lastcount = GetWBack(buf, size);
// RR: Look at wxInputStream for comments.
if (m_lasterror==wxSTREAM_EOF)
- m_lasterror=wxSTREAM_NOERROR;
+ Reset();
if (m_wback)
{
wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
-
+
free(m_wback);
m_wback = NULL;
m_wbacksize = 0;
m_wbackcur = 0;
}
-
+
return m_i_streambuf->Seek(pos, mode);
}
if (pos != wxInvalidOffset)
pos -= (m_wbacksize - m_wbackcur);
-
+
return pos;
}