// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
// general code review
// Created: 11/07/98
-// RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// headers
// ----------------------------------------------------------------------------
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "stream.h"
-#endif
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
- #pragma hdrstop
+ #pragma hdrstop
#endif
+#if wxUSE_STREAMS
+
+#include "wx/stream.h"
+
#ifndef WX_PRECOMP
- #include "wx/defs.h"
+ #include "wx/log.h"
#endif
-#if wxUSE_STREAMS
-
#include <ctype.h>
-#include "wx/stream.h"
#include "wx/datstrm.h"
#include "wx/textfile.h"
-#include "wx/log.h"
+#include "wx/scopeguard.h"
// ----------------------------------------------------------------------------
// constants
m_buffer_start =
m_buffer_end =
m_buffer_pos = NULL;
- m_buffer_size = 0;
// if we are going to allocate the buffer, we should free it later as well
- m_destroybuf = TRUE;
+ m_destroybuf = true;
}
void wxStreamBuffer::Init()
{
InitBuffer();
- m_fixed = TRUE;
+ m_fixed = true;
}
-wxStreamBuffer::wxStreamBuffer(BufMode mode)
+void wxStreamBuffer::InitWithStream(wxStreamBase& stream, BufMode mode)
{
Init();
- m_stream = NULL;
+ m_stream = &stream;
m_mode = mode;
- m_flushable = FALSE;
+ m_flushable = 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_flushable = false;
}
wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
// 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,
- _T("it's a bad idea to copy this buffer") );
+ wxT("it's a bad idea to copy this buffer") );
m_buffer_start = buffer.m_buffer_start;
m_buffer_end = buffer.m_buffer_end;
m_buffer_pos = buffer.m_buffer_pos;
- m_buffer_size = buffer.m_buffer_size;
m_fixed = buffer.m_fixed;
m_flushable = buffer.m_flushable;
m_stream = buffer.m_stream;
m_mode = buffer.m_mode;
- m_destroybuf = FALSE;
+ m_destroybuf = false;
}
void wxStreamBuffer::FreeBuffer()
{
if ( m_destroybuf )
+ {
free(m_buffer_start);
+ m_buffer_start = NULL;
+ }
}
wxStreamBuffer::~wxStreamBuffer()
m_buffer_start = (char *)start;
m_buffer_end = m_buffer_start + len;
- m_buffer_size = len;
-
// if we own it, we free it
m_destroybuf = takeOwnership;
void wxStreamBuffer::SetBufferIO(size_t bufsize)
{
- // start by freeing the old buffer
- FreeBuffer();
-
if ( bufsize )
{
- SetBufferIO(malloc(bufsize), bufsize, TRUE /* take ownership */);
+ // this will free the old buffer and allocate the new one
+ SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */);
}
else // no buffer size => no buffer
{
+ // still free the old one
+ FreeBuffer();
InitBuffer();
}
}
: m_buffer_start;
}
+void wxStreamBuffer::Truncate()
+{
+ size_t new_size = m_buffer_pos - m_buffer_start;
+ if ( m_buffer_pos == m_buffer_end )
+ return;
+
+ if ( !new_size )
+ {
+ FreeBuffer();
+ InitBuffer();
+ return;
+ }
+
+ char *new_start = (char *)realloc(m_buffer_start, new_size);
+ wxCHECK_RET( new_size, wxT("shrinking buffer shouldn't fail") );
+
+ m_buffer_start = new_start;
+ m_buffer_end = m_buffer_start + new_size;
+ m_buffer_pos = m_buffer_end;
+}
+
// fill the buffer with as much data as possible (only for read buffers)
bool wxStreamBuffer::FillBuffer()
{
wxInputStream *inStream = GetInputStream();
- // It's legal to have no stream, so we don't complain about it just return FALSE
+ // It's legal to have no stream, so we don't complain about it just return false
if ( !inStream )
- return FALSE;
+ return false;
- size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
+ size_t count = inStream->OnSysRead(GetBufferStart(), GetBufferSize());
if ( !count )
- return FALSE;
+ return false;
m_buffer_end = m_buffer_start + count;
m_buffer_pos = m_buffer_start;
- return TRUE;
+ return true;
}
// write the buffer contents to the stream (only for write buffers)
bool wxStreamBuffer::FlushBuffer()
{
- wxCHECK_MSG( m_flushable, FALSE, _T("can't flush this buffer") );
+ wxCHECK_MSG( m_flushable, false, wxT("can't flush this buffer") );
// FIXME: what is this check for? (VZ)
if ( m_buffer_pos == m_buffer_start )
- return FALSE;
+ return false;
wxOutputStream *outStream = GetOutputStream();
- wxCHECK_MSG( outStream, FALSE, _T("should have a stream in wxStreamBuffer") );
+ wxCHECK_MSG( outStream, false, wxT("should have a stream in wxStreamBuffer") );
size_t current = m_buffer_pos - m_buffer_start;
size_t count = outStream->OnSysWrite(m_buffer_start, current);
if ( count != current )
- return FALSE;
+ return false;
m_buffer_pos = m_buffer_start;
- return TRUE;
+ return true;
}
size_t wxStreamBuffer::GetDataLeft()
else // !m_fixed
{
// realloc the buffer to have enough space for the data
- size_t delta = m_buffer_pos - m_buffer_start;
-
- char *startOld = m_buffer_start;
- m_buffer_size += size;
- m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
- if ( !m_buffer_start )
+ if ( m_buffer_pos + size > m_buffer_end )
{
- // don't leak memory if realloc() failed
- m_buffer_start = startOld;
- m_buffer_size -= size;
+ size_t delta = m_buffer_pos - m_buffer_start;
+ size_t new_size = delta + size;
- // what else can we do?
- return;
- }
+ char *startOld = m_buffer_start;
+ m_buffer_start = (char *)realloc(m_buffer_start, new_size);
+ if ( !m_buffer_start )
+ {
+ // don't leak memory if realloc() failed
+ m_buffer_start = startOld;
+
+ // what else can we do?
+ return;
+ }
- // adjust the pointers invalidated by realloc()
- m_buffer_pos = m_buffer_start + delta;
- m_buffer_end = m_buffer_start + m_buffer_size;
+ // adjust the pointers invalidated by realloc()
+ m_buffer_pos = m_buffer_start + delta;
+ m_buffer_end = m_buffer_start + new_size;
+ } // else: the buffer is big enough
}
}
{
wxOutputStream *outStream = GetOutputStream();
- wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
+ wxCHECK_RET( outStream, wxT("should have a stream in wxStreamBuffer") );
// if we don't have buffer at all, just forward this call to the stream,
if ( !HasBuffer() )
char wxStreamBuffer::Peek()
{
wxCHECK_MSG( m_stream && HasBuffer(), 0,
- _T("should have the stream and the buffer in wxStreamBuffer") );
+ wxT("should have the stream and the buffer in wxStreamBuffer") );
if ( !GetDataLeft() )
{
{
wxInputStream *inStream = GetInputStream();
- wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
+ wxCHECK_MSG( inStream, 0, wxT("should have a stream in wxStreamBuffer") );
char c;
if ( !HasBuffer() )
size_t wxStreamBuffer::Read(void *buffer, size_t size)
{
+ wxASSERT_MSG( buffer, wxT("Warning: Null pointer is about to be used") );
+
+ /* Clear buffer first */
+ memset(buffer, 0x00, size);
+
// lasterror is reset before all new IO calls
if ( m_stream )
m_stream->Reset();
- size_t read;
+ size_t readBytes;
if ( !HasBuffer() )
{
wxInputStream *inStream = GetInputStream();
- wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
+ wxCHECK_MSG( inStream, 0, wxT("should have a stream in wxStreamBuffer") );
- read = inStream->OnSysRead(buffer, size);
+ readBytes = inStream->OnSysRead(buffer, size);
}
else // we have a buffer, use it
{
}
}
- read = orig_size - size;
+ readBytes = orig_size - size;
}
if ( m_stream )
- m_stream->m_lastcount = read;
+ m_stream->m_lastcount = readBytes;
- return read;
+ return readBytes;
}
// this should really be called "Copy()"
size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
{
- wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
+ wxCHECK_MSG( m_mode != write, 0, wxT("can't read from this buffer") );
char buf[BUF_TEMP_SIZE];
size_t nRead,
do
{
- nRead = Read(dbuf, WXSIZEOF(buf));
+ nRead = Read(buf, WXSIZEOF(buf));
if ( nRead )
{
nRead = dbuf->Write(buf, nRead);
size_t wxStreamBuffer::Write(const void *buffer, size_t size)
{
+ wxASSERT_MSG( buffer, wxT("Warning: Null pointer is about to be send") );
+
if (m_stream)
{
// lasterror is reset before all new IO calls
{
wxOutputStream *outStream = GetOutputStream();
- wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
+ wxCHECK_MSG( outStream, 0, wxT("should have a stream in wxStreamBuffer") );
// no buffer, just forward the call to the stream
ret = outStream->OnSysWrite(buffer, size);
size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
{
- wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
- wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
+ wxCHECK_MSG( m_mode != read, 0, wxT("can't write to this buffer") );
+ wxCHECK_MSG( sbuf->m_mode != write, 0, wxT("can't read from that buffer") );
char buf[BUF_TEMP_SIZE];
size_t nWrite,
return total;
}
-off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
+wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode)
{
- off_t ret_off, diff;
+ wxFileOffset ret_off, diff;
- off_t last_access = GetLastAccess();
+ wxFileOffset last_access = GetLastAccess();
if ( !m_flushable )
{
break;
default:
- wxFAIL_MSG( _T("invalid seek mode") );
+ wxFAIL_MSG( wxT("invalid seek mode") );
return wxInvalidOffset;
}
if (diff < 0 || diff > last_access)
return wxInvalidOffset;
- SetIntPosition(diff);
+ size_t int_diff = wx_truncate_cast(size_t, diff);
+ wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
+ SetIntPosition(int_diff);
return diff;
}
}
else
{
- SetIntPosition(diff);
- return pos;
+ size_t int_diff = wx_truncate_cast(size_t, diff);
+ wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
+ SetIntPosition(int_diff);
+ return diff;
}
case wxFromEnd:
return wxInvalidOffset;
}
-off_t wxStreamBuffer::Tell() const
+wxFileOffset wxStreamBuffer::Tell() const
{
- off_t pos;
+ wxFileOffset pos;
// ask the stream for position if we have a real one
if ( m_stream )
// wxStreamBase
// ----------------------------------------------------------------------------
+IMPLEMENT_ABSTRACT_CLASS(wxStreamBase, wxObject)
+
wxStreamBase::wxStreamBase()
{
m_lasterror = wxSTREAM_NO_ERROR;
{
}
-off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
+size_t wxStreamBase::GetSize() const
+{
+ wxFileOffset length = GetLength();
+ if ( length == (wxFileOffset)wxInvalidOffset )
+ return 0;
+
+ const size_t len = wx_truncate_cast(size_t, length);
+ wxASSERT_MSG( len == length + size_t(0), wxT("large files not supported") );
+
+ return len;
+}
+
+wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
{
return wxInvalidOffset;
}
-off_t wxStreamBase::OnSysTell() const
+wxFileOffset wxStreamBase::OnSysTell() const
{
return wxInvalidOffset;
}
// wxInputStream
// ----------------------------------------------------------------------------
+IMPLEMENT_ABSTRACT_CLASS(wxInputStream, wxStreamBase)
+
wxInputStream::wxInputStream()
{
m_wback = NULL;
size_t wxInputStream::GetWBack(void *buf, size_t size)
{
+ wxASSERT_MSG( buf, wxT("Warning: Null pointer is about to be used") );
+
+ /* Clear buffer first */
+ memset(buf, 0x00, size);
+
if (!m_wback)
return 0;
size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
{
+ wxASSERT_MSG( buf, wxT("Warning: Null pointer is about to be used in Ungetch()") );
+
if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
{
// can't operate on this stream until the error is cleared
if (!ptrback)
return 0;
- // Eof() shouldn't return TRUE any longer
+ // Eof() shouldn't return true any longer
if ( m_lasterror == wxSTREAM_EOF )
m_lasterror = wxSTREAM_NO_ERROR;
return Ungetch(&c, sizeof(c)) != 0;
}
-char wxInputStream::GetC()
+int wxInputStream::GetC()
{
- char c;
+ unsigned char c;
Read(&c, sizeof(c));
- return c;
+ return LastRead() ? c : wxEOF;
}
wxInputStream& wxInputStream::Read(void *buf, size_t size)
{
+ wxASSERT_MSG( buf, wxT("Warning: Null pointer is about to be read") );
+
char *p = (char *)buf;
m_lastcount = 0;
wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
{
+ size_t lastcount = 0;
char buf[BUF_TEMP_SIZE];
for ( ;; )
if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
break;
+
+ lastcount += bytes_read;
}
+ m_lastcount = lastcount;
+
return *this;
}
-off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
+bool wxInputStream::ReadAll(void *buffer_, size_t size)
+{
+ char* buffer = static_cast<char*>(buffer_);
+
+ size_t totalCount = 0;
+
+ for ( ;; )
+ {
+ const size_t lastCount = Read(buffer, size).LastRead();
+
+ // There is no point in continuing looping if we can't read anything at
+ // all.
+ if ( !lastCount )
+ break;
+
+ totalCount += lastCount;
+
+ // ... Or if an error occurred on the stream.
+ if ( !IsOk() )
+ break;
+
+ // Return successfully if we read exactly the requested number of
+ // bytes (normally the ">" case should never occur and so we could use
+ // "==" test, but be safe and avoid overflowing size even in case of
+ // bugs in LastRead()).
+ if ( lastCount >= size )
+ {
+ size = 0;
+ break;
+ }
+
+ // Advance the buffer before trying to read the rest of data.
+ size -= lastCount;
+ buffer += lastCount;
+ }
+
+ m_lastcount = totalCount;
+
+ return size == 0;
+}
+
+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 sought 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
return OnSysSeek(pos, mode);
}
-off_t wxInputStream::TellI() const
+wxFileOffset wxInputStream::TellI() const
{
- off_t pos = OnSysTell();
+ wxFileOffset pos = OnSysTell();
if (pos != wxInvalidOffset)
pos -= (m_wbacksize - m_wbackcur);
// wxOutputStream
// ----------------------------------------------------------------------------
+IMPLEMENT_ABSTRACT_CLASS(wxOutputStream, wxStreamBase)
+
wxOutputStream::wxOutputStream()
{
}
return *this;
}
-off_t wxOutputStream::TellO() const
+bool wxOutputStream::WriteAll(const void *buffer_, size_t size)
+{
+ // This exactly mirrors ReadAll(), see there for more comments.
+ const char* buffer = static_cast<const char*>(buffer_);
+
+ size_t totalCount = 0;
+
+ for ( ;; )
+ {
+ const size_t lastCount = Write(buffer, size).LastWrite();
+ if ( !lastCount )
+ break;
+
+ totalCount += lastCount;
+
+ if ( !IsOk() )
+ break;
+
+ if ( lastCount >= size )
+ {
+ size = 0;
+ break;
+ }
+
+ size -= lastCount;
+ buffer += lastCount;
+ }
+
+ m_lastcount = totalCount;
+ return size == 0;
+}
+
+wxFileOffset wxOutputStream::TellO() const
{
return OnSysTell();
}
-off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
+wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
{
return OnSysSeek(pos, mode);
}
// wxCountingOutputStream
// ----------------------------------------------------------------------------
+IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream, wxOutputStream)
+
wxCountingOutputStream::wxCountingOutputStream ()
{
- m_currentPos = 0;
+ m_currentPos =
+ m_lastPos = 0;
}
-size_t wxCountingOutputStream::GetSize() const
+wxFileOffset wxCountingOutputStream::GetLength() const
{
- return m_lastcount;
+ return m_lastPos;
}
size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
size_t size)
{
m_currentPos += size;
- if (m_currentPos > m_lastcount)
- m_lastcount = m_currentPos;
+ if ( m_currentPos > m_lastPos )
+ m_lastPos = m_currentPos;
- return m_currentPos;
+ return size;
}
-off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
+wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
{
+ ssize_t new_pos = wx_truncate_cast(ssize_t, pos);
+
switch ( mode )
{
case wxFromStart:
- m_currentPos = pos;
+ wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") );
break;
case wxFromEnd:
- m_currentPos = m_lastcount + pos;
+ new_pos += m_lastPos;
+ wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastPos + pos), wxInvalidOffset, wxT("huge position not supported") );
break;
case wxFromCurrent:
- m_currentPos += pos;
+ new_pos += m_currentPos;
+ wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") );
break;
default:
- wxFAIL_MSG( _T("invalid seek mode") );
+ wxFAIL_MSG( wxT("invalid seek mode") );
return wxInvalidOffset;
}
- if (m_currentPos > m_lastcount)
- m_lastcount = m_currentPos;
+ m_currentPos = new_pos;
+
+ if ( m_currentPos > m_lastPos )
+ m_lastPos = m_currentPos;
return m_currentPos;
}
-off_t wxCountingOutputStream::OnSysTell() const
+wxFileOffset wxCountingOutputStream::OnSysTell() const
{
return m_currentPos;
}
// wxFilterInputStream
// ----------------------------------------------------------------------------
+IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream, wxInputStream)
+
wxFilterInputStream::wxFilterInputStream()
+ : m_parent_i_stream(NULL),
+ m_owns(false)
{
- m_parent_i_stream = NULL;
}
wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
+ : m_parent_i_stream(&stream),
+ m_owns(false)
+{
+}
+
+wxFilterInputStream::wxFilterInputStream(wxInputStream *stream)
+ : m_parent_i_stream(stream),
+ m_owns(true)
{
- m_parent_i_stream = &stream;
}
wxFilterInputStream::~wxFilterInputStream()
{
+ if (m_owns)
+ delete m_parent_i_stream;
}
// ----------------------------------------------------------------------------
// wxFilterOutputStream
// ----------------------------------------------------------------------------
+IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream, wxOutputStream)
+
wxFilterOutputStream::wxFilterOutputStream()
+ : m_parent_o_stream(NULL),
+ m_owns(false)
{
- m_parent_o_stream = NULL;
}
wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
+ : m_parent_o_stream(&stream),
+ m_owns(false)
+{
+}
+
+wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream)
+ : m_parent_o_stream(stream),
+ m_owns(true)
{
- m_parent_o_stream = &stream;
+}
+
+bool wxFilterOutputStream::Close()
+{
+ if (m_parent_o_stream && m_owns)
+ return m_parent_o_stream->Close();
+ else
+ return true;
}
wxFilterOutputStream::~wxFilterOutputStream()
{
+ if (m_owns)
+ delete m_parent_o_stream;
}
// ----------------------------------------------------------------------------
-// wxBufferedInputStream
+// wxFilterClassFactoryBase
// ----------------------------------------------------------------------------
-wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
- wxStreamBuffer *buffer)
- : wxFilterInputStream(s)
+IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject)
+
+wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const
{
- if ( buffer )
+ return location.substr(0, FindExtension(location));
+}
+
+wxString::size_type wxFilterClassFactoryBase::FindExtension(
+ const wxString& location) const
+{
+ for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++)
{
- // use the buffer provided by the user
- m_i_streambuf = buffer;
+ if ( location.EndsWith(*p) )
+ return location.length() - wxStrlen(*p);
}
- else // create a default buffer
+
+ return wxString::npos;
+}
+
+bool wxFilterClassFactoryBase::CanHandle(const wxString& protocol,
+ wxStreamProtocolType type) const
+{
+ if (type == wxSTREAM_FILEEXT)
+ return FindExtension(protocol) != wxString::npos;
+ else
+ for (const wxChar *const *p = GetProtocols(type); *p; p++)
+ if (protocol == *p)
+ return true;
+
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+// wxFilterClassFactory
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase)
+
+wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL;
+
+void wxFilterClassFactory::Remove()
+{
+ if (m_next != this)
{
- m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
+ wxFilterClassFactory **pp = &sm_first;
+
+ while (*pp != this)
+ pp = &(*pp)->m_next;
+
+ *pp = m_next;
- m_i_streambuf->SetBufferIO(1024);
+ m_next = this;
}
}
+// ----------------------------------------------------------------------------
+// wxBufferedInputStream
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// helper function used for initializing the buffer used by
+// wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
+// not NULL or creates a buffer of the given size otherwise
+template <typename T>
+wxStreamBuffer *
+CreateBufferIfNeeded(T& stream, wxStreamBuffer *buffer, size_t bufsize = 1024)
+{
+ return buffer ? buffer : new wxStreamBuffer(bufsize, stream);
+}
+
+} // anonymous namespace
+
+wxBufferedInputStream::wxBufferedInputStream(wxInputStream& stream,
+ wxStreamBuffer *buffer)
+ : wxFilterInputStream(stream)
+{
+ m_i_streambuf = CreateBufferIfNeeded(*this, buffer);
+}
+
+wxBufferedInputStream::wxBufferedInputStream(wxInputStream& stream,
+ size_t bufsize)
+ : wxFilterInputStream(stream)
+{
+ m_i_streambuf = CreateBufferIfNeeded(*this, NULL, bufsize);
+}
+
wxBufferedInputStream::~wxBufferedInputStream()
{
- m_parent_i_stream->SeekI(-(off_t)m_i_streambuf->GetBytesLeft(),
+ m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
wxFromCurrent);
delete m_i_streambuf;
size -= m_lastcount;
buf = (char *)buf + m_lastcount;
- // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
- // so save it
+ // the call to wxStreamBuffer::Read() below may reset our m_lastcount
+ // (but it also may not do it if the buffer is associated to another
+ // existing stream and wasn't created by us), so save it
size_t countOld = m_lastcount;
- m_i_streambuf->Read(buf, size);
+ // the new count of the bytes read is the count of bytes read this time
+ m_lastcount = m_i_streambuf->Read(buf, size);
+ // plus those we had read before
m_lastcount += countOld;
}
return *this;
}
-off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
+wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
{
// RR: Look at wxInputStream for comments.
return m_i_streambuf->Seek(pos, mode);
}
-off_t wxBufferedInputStream::TellI() const
+wxFileOffset wxBufferedInputStream::TellI() const
{
- off_t pos = m_i_streambuf->Tell();
+ wxFileOffset pos = m_i_streambuf->Tell();
if (pos != wxInvalidOffset)
pos -= (m_wbacksize - m_wbackcur);
return m_parent_i_stream->Read(buffer, bufsize).LastRead();
}
-off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
+wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
{
return m_parent_i_stream->SeekI(seek, mode);
}
-off_t wxBufferedInputStream::OnSysTell() const
+wxFileOffset wxBufferedInputStream::OnSysTell() const
{
return m_parent_i_stream->TellI();
}
void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
{
- wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
+ wxCHECK_RET( buffer, wxT("wxBufferedInputStream needs buffer") );
delete m_i_streambuf;
m_i_streambuf = buffer;
// wxBufferedOutputStream
// ----------------------------------------------------------------------------
-wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
+wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& stream,
wxStreamBuffer *buffer)
- : wxFilterOutputStream(s)
+ : wxFilterOutputStream(stream)
{
- if ( buffer )
- {
- m_o_streambuf = buffer;
- }
- else // create a default one
- {
- m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
+ m_o_streambuf = CreateBufferIfNeeded(*this, buffer);
+}
- m_o_streambuf->SetBufferIO(1024);
- }
+wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& stream,
+ size_t bufsize)
+ : wxFilterOutputStream(stream)
+{
+ m_o_streambuf = CreateBufferIfNeeded(*this, NULL, bufsize);
}
wxBufferedOutputStream::~wxBufferedOutputStream()
delete m_o_streambuf;
}
+bool wxBufferedOutputStream::Close()
+{
+ Sync();
+ return IsOk();
+}
+
+
wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
{
m_lastcount = 0;
return *this;
}
-off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
+wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
{
Sync();
return m_o_streambuf->Seek(pos, mode);
}
-off_t wxBufferedOutputStream::TellO() const
+wxFileOffset wxBufferedOutputStream::TellO() const
{
return m_o_streambuf->Tell();
}
return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
}
-off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
+wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
{
return m_parent_o_stream->SeekO(seek, mode);
}
-off_t wxBufferedOutputStream::OnSysTell() const
+wxFileOffset wxBufferedOutputStream::OnSysTell() const
{
return m_parent_o_stream->TellO();
}
-size_t wxBufferedOutputStream::GetSize() const
+wxFileOffset wxBufferedOutputStream::GetLength() const
{
- return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
+ return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition();
}
void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
{
- wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
+ wxCHECK_RET( buffer, wxT("wxBufferedOutputStream needs buffer") );
delete m_o_streambuf;
m_o_streambuf = buffer;
}
+// ---------------------------------------------------------------------------
+// wxWrapperInputStream implementation
+// ---------------------------------------------------------------------------
+
+wxWrapperInputStream::wxWrapperInputStream()
+{
+ m_lasterror = wxSTREAM_READ_ERROR;
+}
+
+wxWrapperInputStream::wxWrapperInputStream(wxInputStream& stream)
+ : wxFilterInputStream(stream)
+{
+ SynchronizeLastError();
+}
+
+wxWrapperInputStream::wxWrapperInputStream(wxInputStream *stream)
+ : wxFilterInputStream(stream)
+{
+ if ( m_parent_i_stream )
+ SynchronizeLastError();
+ else
+ m_lasterror = wxSTREAM_READ_ERROR;
+}
+
+void wxWrapperInputStream::InitParentStream(wxInputStream& stream)
+{
+ wxCHECK_RET( !m_parent_i_stream, "Can't init parent stream twice" );
+
+ m_parent_i_stream = &stream;
+
+ SynchronizeLastError();
+}
+
+void wxWrapperInputStream::InitParentStream(wxInputStream* stream)
+{
+ wxCHECK_RET( !m_parent_i_stream, "Can't init parent stream twice" );
+
+ m_parent_i_stream = stream;
+
+ if ( m_parent_i_stream )
+ {
+ m_owns = true;
+
+ SynchronizeLastError();
+ }
+}
+
+wxFileOffset wxWrapperInputStream::GetLength() const
+{
+ wxCHECK_MSG(m_parent_i_stream, wxInvalidOffset, "Stream not valid");
+
+ wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
+ return m_parent_i_stream->GetLength();
+}
+
+bool wxWrapperInputStream::IsSeekable() const
+{
+ wxCHECK_MSG(m_parent_i_stream, false, "Stream not valid");
+ return m_parent_i_stream->IsSeekable();
+}
+
+size_t wxWrapperInputStream::OnSysRead(void *buffer, size_t size)
+{
+ wxCHECK_MSG(m_parent_i_stream, false, "Stream not valid");
+
+ wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
+
+ m_parent_i_stream->Read(buffer, size);
+ return m_parent_i_stream->LastRead();
+}
+
+wxFileOffset wxWrapperInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
+{
+ wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
+
+ wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
+ return m_parent_i_stream->SeekI (pos, mode);
+}
+
+wxFileOffset wxWrapperInputStream::OnSysTell() const
+{
+ wxCHECK_MSG(m_parent_i_stream, false, "Stream not valid");
+
+ wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
+ return m_parent_i_stream->TellI();
+}
+
// ----------------------------------------------------------------------------
// Some IOManip function
// ----------------------------------------------------------------------------
return stream.Write(eol, wxStrlen(eol));
}
-#endif
- // wxUSE_STREAMS
+#endif // wxUSE_STREAMS