X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e3eca9d3782d5eed5ba8d8019548c9f82523517..e421922f90186d0619a806d277a0a2182e61b5fb:/src/common/stream.cpp diff --git a/src/common/stream.cpp b/src/common/stream.cpp index 4d32e503ea..9763842c4a 100644 --- a/src/common/stream.cpp +++ b/src/common/stream.cpp @@ -1,16 +1,25 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: stream.cpp +// Name: src/common/stream.cpp // Purpose: wxStream base classes // Author: Guilhem Lavaux -// Modified by: +// 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 license ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "stream.h" + #pragma implementation "stream.h" #endif // For compilers that support precompilation, includes "wx.h". @@ -27,461 +36,585 @@ #if wxUSE_STREAMS #include -#include -#include -#include +#include "wx/stream.h" +#include "wx/datstrm.h" +#include "wx/objstrm.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- +// the temporary buffer size used when copying from stream to stream #define BUF_TEMP_SIZE 10000 +// ============================================================================ +// implementation +// ============================================================================ + // ---------------------------------------------------------------------------- // wxStreamBuffer // ---------------------------------------------------------------------------- -#define CHECK_ERROR(err) \ - if (m_stream->m_lasterror == wxStream_NOERROR) \ - m_stream->m_lasterror = err - -wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) - : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL), - m_buffer_size(0), m_wback(NULL), m_wbacksize(0), m_wbackcur(0), - m_fixed(TRUE), m_flushable(TRUE), m_stream(&stream), - m_mode(mode), m_destroybuf(FALSE), m_destroystream(FALSE) +void wxStreamBuffer::SetError(wxStreamError err) { + if ( m_stream->m_lasterror == wxStream_NOERROR ) + m_stream->m_lasterror = err; } -wxStreamBuffer::wxStreamBuffer(BufMode mode) - : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL), - m_buffer_size(0), m_wback(NULL), m_wbacksize(0), m_wbackcur(0), - m_fixed(TRUE), m_flushable(FALSE), m_stream(NULL), - m_mode(mode), m_destroybuf(FALSE), m_destroystream(TRUE) +void wxStreamBuffer::InitBuffer() { - m_stream = new wxStreamBase(); -} + m_buffer_start = + m_buffer_end = + m_buffer_pos = NULL; + m_buffer_size = 0; -wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& 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_destroystream = FALSE; - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; + // there is nothing to destroy anyhow + m_destroybuf = FALSE; } -wxStreamBuffer::~wxStreamBuffer() +void wxStreamBuffer::Init() { - if (m_wback) - free(m_wback); - if (m_destroybuf) - wxDELETEA(m_buffer_start); - if (m_destroystream) - delete m_stream; + InitBuffer(); + + m_fixed = TRUE; } -size_t wxStreamBuffer::WriteBack(const char *buf, size_t bufsize) +wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) { - char *ptrback; + Init(); - if (m_mode != read) - return 0; + m_stream = &stream; + m_mode = mode; - ptrback = AllocSpaceWBack(bufsize); - if (!ptrback) - return 0; - - memcpy(ptrback, buf, bufsize); - return bufsize; + m_flushable = TRUE; + m_destroystream = FALSE; } -bool wxStreamBuffer::WriteBack(char c) +wxStreamBuffer::wxStreamBuffer(BufMode mode) { - char *ptrback; + Init(); - ptrback = AllocSpaceWBack(1); - if (!ptrback) - return FALSE; + m_stream = new wxStreamBase; + m_mode = mode; - *ptrback = c; - return TRUE; + m_flushable = FALSE; + m_destroystream = TRUE; } -void wxStreamBuffer::SetBufferIO(char *buffer_start, char *buffer_end) +wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer) { - if (m_destroybuf) - wxDELETEA(m_buffer_start); - m_buffer_start = buffer_start; - m_buffer_end = buffer_end; + // doing this has big chances to lead to a crashwhen the source buffer is + // destroyed (otherwise assume the caller knows what he does) + wxASSERT_MSG( !buffer.m_destroybuf && !buffer.m_destroystream, + _T("it's a bad idea to copy this buffer") ); - m_buffer_size = m_buffer_end-m_buffer_start; - m_destroybuf = FALSE; - ResetBuffer(); + 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_destroystream = FALSE; } -void wxStreamBuffer::SetBufferIO(size_t bufsize) +void wxStreamBuffer::FreeBuffer() { - char *b_start; + if ( m_destroybuf ) + free(m_buffer_start); +} - if (m_destroybuf) - wxDELETEA(m_buffer_start); +wxStreamBuffer::~wxStreamBuffer() +{ + FreeBuffer(); - if (!bufsize) { - m_buffer_start = NULL; - m_buffer_end = NULL; - m_buffer_pos = NULL; - m_buffer_size = 0; - return; - } + if ( m_destroystream ) + delete m_stream; +} - b_start = new char[bufsize]; - SetBufferIO(b_start, b_start + bufsize); - m_destroybuf = TRUE; +wxInputStream *wxStreamBuffer::GetInputStream() const +{ + return m_mode == write ? NULL : (wxInputStream *)m_stream; } -void wxStreamBuffer::ResetBuffer() +wxOutputStream *wxStreamBuffer::GetOutputStream() const { - m_stream->m_lasterror = wxStream_NOERROR; - m_stream->m_lastcount = 0; - if (m_mode == read) - m_buffer_pos = m_buffer_end; - else - m_buffer_pos = m_buffer_start; + return m_mode == read ? NULL : (wxOutputStream *)m_stream; } -char *wxStreamBuffer::AllocSpaceWBack(size_t needed_size) +void wxStreamBuffer::SetBufferIO(void *buffer_start, + void *buffer_end, + bool takeOwnership) { - char *temp_b; + SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start, + takeOwnership); +} - m_wbacksize += needed_size; +void wxStreamBuffer::SetBufferIO(void *start, + size_t len, + bool takeOwnership) +{ + // start by freeing the old buffer + FreeBuffer(); - if (!m_wback) - temp_b = (char *)malloc(m_wbacksize); - else - temp_b = (char *)realloc(m_wback, m_wbacksize); + m_buffer_start = (char *)start; + m_buffer_end = m_buffer_start + len; - if (!temp_b) - return NULL; - m_wback = temp_b; - - return (char *)(m_wback+(m_wbacksize-needed_size)); + m_buffer_size = len; + + // if we own it, we free it + m_destroybuf = takeOwnership; + + ResetBuffer(); } -size_t wxStreamBuffer::GetWBack(char *buf, size_t bsize) +void wxStreamBuffer::SetBufferIO(size_t bufsize) { - size_t s_toget = m_wbacksize-m_wbackcur; + // start by freeing the old buffer + FreeBuffer(); - if (bsize < s_toget) - s_toget = bsize; + if ( bufsize ) + { + SetBufferIO(malloc(bufsize), bufsize, TRUE /* take ownership */); + } + else // no buffer size => no buffer + { + InitBuffer(); + } +} - memcpy(buf, (m_wback+m_wbackcur), s_toget); +void wxStreamBuffer::ResetBuffer() +{ + wxCHECK_RET( m_stream, _T("should have a stream in wxStreamBuffer") ); - m_wbackcur += s_toget; - if (m_wbackcur == m_wbacksize) { - free(m_wback); - m_wback = (char *)NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - return s_toget; + 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; } +// fill the buffer with as much data as possible (only for read buffers) bool wxStreamBuffer::FillBuffer() { - size_t count; + wxInputStream *inStream = GetInputStream(); - count = m_stream->OnSysRead(m_buffer_start, m_buffer_size); - m_buffer_end = m_buffer_start+count; - m_buffer_pos = m_buffer_start; + wxCHECK_MSG( inStream, FALSE, _T("should have a stream in wxStreamBuffer") ); - if (count == 0) - return FALSE; - return TRUE; + size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size); + if ( !count ) + return FALSE; + + m_buffer_end = m_buffer_start + count; + m_buffer_pos = m_buffer_start; + + return TRUE; } +// write the buffer contents to the stream (only for write buffers) bool wxStreamBuffer::FlushBuffer() { - size_t count, current; + wxCHECK_MSG( m_flushable, FALSE, _T("can't flush this buffer") ); - if (m_buffer_pos == m_buffer_start || !m_flushable) - return FALSE; + // FIXME: what is this check for? (VZ) + if ( m_buffer_pos == m_buffer_start ) + return FALSE; - current = m_buffer_pos-m_buffer_start; - count = m_stream->OnSysWrite(m_buffer_start, current); - if (count != current) - return FALSE; - m_buffer_pos = m_buffer_start; + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_MSG( outStream, FALSE, _T("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 TRUE; + m_buffer_pos = m_buffer_start; + + return TRUE; } +size_t wxStreamBuffer::GetDataLeft() +{ + /* Why is this done? RR. */ + if ( m_buffer_pos == m_buffer_end && m_flushable) + FillBuffer(); + + return GetBytesLeft(); +} + +// copy up to size bytes from our buffer into the provided one void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size) { - size_t s_toget = m_buffer_end-m_buffer_pos; + // don't get more bytes than left in the buffer + size_t left = GetBytesLeft(); - if (size < s_toget) - s_toget = size; + if ( size > left ) + size = left; - memcpy(buffer, m_buffer_pos, s_toget); - m_buffer_pos += s_toget; + memcpy(buffer, m_buffer_pos, size); + m_buffer_pos += size; } +// copy the contents of the provided buffer into this one void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size) { - size_t s_toput = m_buffer_end-m_buffer_pos; + size_t left = GetBytesLeft(); + if ( size > left ) + { + if ( m_fixed ) + { + // we can't realloc the buffer, so just copy what we can + size = left; + } + 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 ) + { + // don't leak memory if realloc() failed + m_buffer_start = startOld; + m_buffer_size -= size; + + // 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; + } + } - if (s_toput < size && !m_fixed) { - m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size+size); - // I round a bit - m_buffer_size += size; - m_buffer_end = m_buffer_start+m_buffer_size; - s_toput = size; - } - if (s_toput > size) - s_toput = size; - memcpy(m_buffer_pos, buffer, s_toput); - m_buffer_pos += s_toput; + memcpy(m_buffer_pos, buffer, size); + m_buffer_pos += size; } void wxStreamBuffer::PutChar(char c) { - wxASSERT(m_stream != NULL); - - if (!m_buffer_size) { - m_stream->OnSysWrite(&c, 1); - return; - } + wxOutputStream *outStream = GetOutputStream(); - if (GetDataLeft() == 0 && !FlushBuffer()) { - CHECK_ERROR(wxStream_WRITE_ERR); - return; - } + wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") ); - PutToBuffer(&c, 1); - m_stream->m_lastcount = 1; + // if we don't have buffer at all, just forward this call to the stream, + if ( !HasBuffer() ) + { + outStream->OnSysWrite(&c, 1); + } + else + { + // otherwise check we have enough space left + if ( !GetDataLeft() && !FlushBuffer() ) + { + // we don't + SetError(wxStream_WRITE_ERR); + } + else + { + PutToBuffer(&c, 1); + m_stream->m_lastcount = 1; + } + } } -char wxStreamBuffer::GetChar() +char wxStreamBuffer::Peek() { - char c; + wxCHECK_MSG( m_stream && HasBuffer(), 0, + _T("should have the stream and the buffer in wxStreamBuffer") ); - wxASSERT(m_stream != NULL); - - if (!m_buffer_size) { - m_stream->OnSysRead(&c, 1); - return c; - } + if ( !GetDataLeft() ) + { + SetError(wxStream_READ_ERR); + return 0; + } - if (!GetDataLeft()) { - CHECK_ERROR(wxStream_READ_ERR); - return 0; - } + char c; + GetFromBuffer(&c, 1); + m_buffer_pos--; - GetFromBuffer(&c, 1); - - m_stream->m_lastcount = 1; - return c; + return c; } -size_t wxStreamBuffer::Read(void *buffer, size_t size) +char wxStreamBuffer::GetChar() { - wxASSERT(m_stream != NULL); - - if (m_mode == write) - return 0; - - // ------------------ - // Buffering disabled - // ------------------ - - m_stream->m_lasterror = wxStream_NOERROR; - m_stream->m_lastcount = GetWBack((char *)buffer, size); - size -= m_stream->m_lastcount; - if (size == 0) - return m_stream->m_lastcount; + wxInputStream *inStream = GetInputStream(); - buffer = (void *)((char *)buffer+m_stream->m_lastcount); + wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); - if (!m_buffer_size) - return (m_stream->m_lastcount += m_stream->OnSysRead(buffer, size)); + char c; + if ( !HasBuffer() ) + { + inStream->OnSysRead(&c, 1); + } + else + { + if ( !GetDataLeft() ) + { + SetError(wxStream_READ_ERR); + c = 0; + } + else + { + GetFromBuffer(&c, 1); + m_stream->m_lastcount = 1; + } + } - // ----------------- - // Buffering enabled - // ----------------- - size_t buf_left, orig_size = size; + return c; +} - while (size > 0) { - buf_left = GetDataLeft(); +size_t wxStreamBuffer::Read(void *buffer, size_t size) +{ + wxInputStream *inStream = GetInputStream(); - // First case: the requested buffer is larger than the stream buffer, - // we split it. - if (size > buf_left) { - GetFromBuffer(buffer, buf_left); - size -= buf_left; - buffer = (char *)buffer + buf_left; // ANSI C++ violation. + wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); - if (!FillBuffer()) { - CHECK_ERROR(wxStream_READ_ERR); - return (m_stream->m_lastcount = orig_size-size); - } - } else { + // lasterror is reset before all new IO calls + m_stream->m_lasterror = wxStream_NOERROR; - // Second case: we just copy from the stream buffer. - GetFromBuffer(buffer, size); - break; + if ( !HasBuffer() ) + { + m_stream->m_lastcount = inStream->OnSysRead(buffer, size); + } + else // we have a buffer, use it + { + size_t orig_size = size; + + while ( size > 0 ) + { + size_t left = GetDataLeft(); + + // if the requested number of bytes if greater than the buffer + // size, read data in chunks + if ( size > left ) + { + GetFromBuffer(buffer, left); + size -= left; + buffer = (char *)buffer + left; + + if ( !FillBuffer() ) + { + SetError(wxStream_EOF); + break; + } + } + else // otherwise just do it in one gulp + { + GetFromBuffer(buffer, size); + size = 0; + } + } + + m_stream->m_lastcount = orig_size - size; } - } - return (m_stream->m_lastcount += orig_size); + + return m_stream->m_lastcount; } -size_t wxStreamBuffer::Read(wxStreamBuffer *s_buf) +// this should really be called "Copy()" +size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf) { - char buf[BUF_TEMP_SIZE]; - size_t s = 0, bytes_read = BUF_TEMP_SIZE; + wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") ); - if (m_mode == write) - return 0; + char buf[BUF_TEMP_SIZE]; + size_t nRead, + total = 0; + + do + { + nRead = Read(dbuf, WXSIZEOF(buf)); + if ( nRead ) + { + nRead = dbuf->Write(buf, nRead); + total += nRead; + } + } + while ( nRead ); - while (bytes_read != 0) { - bytes_read = Read(buf, bytes_read); - bytes_read = s_buf->Write(buf, bytes_read); - s += bytes_read; - } - return s; + return total; } size_t wxStreamBuffer::Write(const void *buffer, size_t size) { - wxASSERT(m_stream != NULL); + wxOutputStream *outStream = GetOutputStream(); - if (m_mode == read) - return 0; + wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") ); - // ------------------ - // Buffering disabled - // ------------------ + // lasterror is reset before all new IO calls + m_stream->m_lasterror = wxStream_NOERROR; - m_stream->m_lasterror = wxStream_NOERROR; - if (!m_buffer_size) - return (m_stream->m_lastcount = m_stream->OnSysWrite(buffer, size)); - - // ------------------ - // Buffering enabled - // ------------------ - - size_t buf_left, orig_size = size; - - while (size > 0) { - buf_left = m_buffer_end - m_buffer_pos; - - // First case: the buffer to write is larger than the stream buffer, - // we split it - if (size > buf_left) { - PutToBuffer(buffer, buf_left); - size -= buf_left; - buffer = (char *)buffer + buf_left; // ANSI C++ violation. - - if (!FlushBuffer()) { - CHECK_ERROR(wxStream_WRITE_ERR); - return (m_stream->m_lastcount = orig_size-size); - } - - m_buffer_pos = m_buffer_start; - - } else { - - // Second case: just copy it in the stream buffer. - PutToBuffer(buffer, size); - break; + if ( !HasBuffer() && m_fixed ) + { + // no buffer, just forward the call to the stream + m_stream->m_lastcount = outStream->OnSysWrite(buffer, size); + } + else // we [may] have a buffer, use it + { + size_t orig_size = size; + + while ( size > 0 ) + { + size_t left = GetBytesLeft(); + + // if the buffer is too large to fit in the stream buffer, split + // it in smaller parts + // + // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream), + // we always go to the second case. + // + // 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); + size -= left; + buffer = (char *)buffer + left; + + if ( !FlushBuffer() ) + { + SetError(wxStream_WRITE_ERR); + + break; + } + + m_buffer_pos = m_buffer_start; + } + else // we can do it in one gulp + { + PutToBuffer(buffer, size); + size = 0; + } + } + + m_stream->m_lastcount = orig_size - size; } - } - return (m_stream->m_lastcount = orig_size); + + return m_stream->m_lastcount; } size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf) { - char buf[BUF_TEMP_SIZE]; - size_t s = 0, bytes_count = BUF_TEMP_SIZE, b_count2; - - if (m_mode == read) - return 0; + 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") ); + + char buf[BUF_TEMP_SIZE]; + size_t nWrite, + total = 0; + + do + { + size_t nRead = sbuf->Read(buf, WXSIZEOF(buf)); + if ( nRead ) + { + nWrite = Write(buf, nRead); + if ( nWrite < nRead ) + { + // put back data we couldn't copy + wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream(); + + in_stream->Ungetch(buf + nWrite, nRead - nWrite); + } + + total += nWrite; + } + else + { + nWrite = 0; + } + } + while ( nWrite == WXSIZEOF(buf) ); - while (bytes_count == BUF_TEMP_SIZE) { - b_count2 = sbuf->Read(buf, bytes_count); - bytes_count = Write(buf, b_count2); - if (b_count2 > bytes_count) - sbuf->WriteBack(buf+bytes_count, b_count2-bytes_count); - s += bytes_count; - } - return s; + return total; } off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode) { - off_t ret_off, diff, last_access; + off_t ret_off, diff; - last_access = GetLastAccess(); + off_t last_access = GetLastAccess(); - if (!m_flushable) { - diff = pos + GetIntPosition(); - if (diff < 0 || diff > last_access) - return wxInvalidOffset; - SetIntPosition(diff); - return diff; - } + if ( !m_flushable ) + { + switch (mode) + { + case wxFromStart: + diff = pos; + break; - switch (mode) { - case wxFromStart: { - // We'll try to compute an internal position later ... - ret_off = m_stream->OnSysSeek(pos, wxFromStart); - ResetBuffer(); - return ret_off; - } - case wxFromCurrent: { - diff = pos + GetIntPosition(); - - if ( (diff > last_access) || (diff < 0) ) { - ret_off = m_stream->OnSysSeek(pos, wxFromCurrent); - ResetBuffer(); - return ret_off; - } else { - SetIntPosition(diff); - return pos; + case wxFromCurrent: + diff = pos + GetIntPosition(); + break; + + case wxFromEnd: + diff = pos + last_access; + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + + return wxInvalidOffset; + } + if (diff < 0 || diff > last_access) + return wxInvalidOffset; + SetIntPosition(diff); + return diff; } - } - case wxFromEnd: - // Hard to compute: always seek to the requested position. - ret_off = m_stream->OnSysSeek(pos, wxFromEnd); - ResetBuffer(); - return ret_off; - } - return wxInvalidOffset; + + switch ( mode ) + { + case wxFromStart: + // We'll try to compute an internal position later ... + ret_off = m_stream->OnSysSeek(pos, wxFromStart); + ResetBuffer(); + return ret_off; + + case wxFromCurrent: + diff = pos + GetIntPosition(); + + if ( (diff > last_access) || (diff < 0) ) + { + // We must take into account the fact that we have read + // something previously. + ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent); + ResetBuffer(); + return ret_off; + } + else + { + SetIntPosition(diff); + return pos; + } + + case wxFromEnd: + // Hard to compute: always seek to the requested position. + ret_off = m_stream->OnSysSeek(pos, wxFromEnd); + ResetBuffer(); + return ret_off; + } + + return wxInvalidOffset; } off_t wxStreamBuffer::Tell() const { - off_t pos; + off_t pos = m_stream->OnSysTell(); + if ( pos == wxInvalidOffset ) + return wxInvalidOffset; - if (m_flushable) { - pos = m_stream->OnSysTell(); - if (pos == wxInvalidOffset) - return wxInvalidOffset; - return pos - GetLastAccess() + GetIntPosition(); - } else - return GetIntPosition(); -} + pos += GetIntPosition(); -size_t wxStreamBuffer::GetDataLeft() -{ - if (m_buffer_end == m_buffer_pos && m_flushable) - FillBuffer(); - return m_buffer_end-m_buffer_pos; + if ( m_mode == read && m_flushable ) + pos -= GetLastAccess(); + + return pos; } // ---------------------------------------------------------------------------- @@ -490,32 +623,22 @@ size_t wxStreamBuffer::GetDataLeft() wxStreamBase::wxStreamBase() { - m_lasterror = wxStream_NOERROR; - m_lastcount = 0; + m_lasterror = wxStream_NOERROR; + m_lastcount = 0; } wxStreamBase::~wxStreamBase() { } -size_t wxStreamBase::OnSysRead(void *WXUNUSED(buffer), size_t WXUNUSED(size)) -{ - return 0; -} - -size_t wxStreamBase::OnSysWrite(const void *WXUNUSED(buffer), size_t WXUNUSED(bufsize)) -{ - return 0; -} - off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode)) { - return wxInvalidOffset; + return wxInvalidOffset; } off_t wxStreamBase::OnSysTell() const { - return wxInvalidOffset; + return wxInvalidOffset; } // ---------------------------------------------------------------------------- @@ -523,440 +646,528 @@ off_t wxStreamBase::OnSysTell() const // ---------------------------------------------------------------------------- wxInputStream::wxInputStream() - : wxStreamBase() { - m_i_destroybuf = TRUE; - m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); + m_wback = NULL; + m_wbacksize = + m_wbackcur = 0; } -wxInputStream::wxInputStream(wxStreamBuffer *buffer) - : wxStreamBase() +wxInputStream::~wxInputStream() { - m_i_destroybuf = FALSE; - m_i_streambuf = buffer; + free(m_wback); } -wxInputStream::~wxInputStream() +size_t wxInputStream::OnSysRead(void * WXUNUSED(buffer), + size_t WXUNUSED(bufsize)) { - if (m_i_destroybuf) - delete m_i_streambuf; + return 0; } -char wxInputStream::GetC() +bool wxInputStream::Eof() const { - char c; - m_i_streambuf->Read(&c, 1); - return c; + 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; } +char *wxInputStream::AllocSpaceWBack(size_t needed_size) +{ + // get number of bytes left from previous wback buffer + size_t toget = m_wbacksize - m_wbackcur; + + // allocate a buffer large enough to hold prev + new data + char *temp_b = (char *)malloc(needed_size + toget); + + if (!temp_b) + return NULL; -wxString wxInputStream::ReadLine() + /* copy previous data (and free old buffer) if needed */ + if (m_wback) + { + memmove(temp_b + needed_size, m_wback + m_wbackcur, toget); + free(m_wback); + } + + /* done */ + m_wback = temp_b; + m_wbackcur = 0; + m_wbacksize = needed_size + toget; + + return m_wback; +} + +size_t wxInputStream::GetWBack(void *buf, size_t bsize) { - char c, last_endl = 0; - bool end_line = FALSE; - wxString line; + size_t toget = m_wbacksize-m_wbackcur; + + if (!m_wback) + return 0; - while (!end_line) { - c = GetC(); - if (LastError() != wxStream_NOERROR) - break; + if (bsize < toget) + toget = bsize; - switch (c) { - case '\n': - end_line = TRUE; - break; - case '\r': - last_endl = '\r'; - break; - default: - if (last_endl == '\r') { - end_line = TRUE; - InputStreamBuffer()->WriteBack(c); - break; - } - line += c; - break; - } - } - return line; + memcpy(buf, (m_wback+m_wbackcur), toget); + + m_wbackcur += toget; + if (m_wbackcur == m_wbacksize) + { + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + return toget; } -wxInputStream& wxInputStream::Read(void *buffer, size_t size) +size_t wxInputStream::Ungetch(const void *buf, size_t bufsize) { - m_i_streambuf->Read(buffer, size); - // wxStreamBuffer sets all variables for us - return *this; + char *ptrback = AllocSpaceWBack(bufsize); + if (!ptrback) + return 0; + + memcpy(ptrback, buf, bufsize); + return bufsize; } -char wxInputStream::Peek() +bool wxInputStream::Ungetch(char c) { - m_i_streambuf->GetDataLeft(); + void *ptrback = AllocSpaceWBack(1); + if (!ptrback) + return FALSE; - return *(m_i_streambuf->GetBufferPos()); + *(char *)ptrback = c; + return TRUE; +} + +char wxInputStream::GetC() +{ + char c; + Read(&c, 1); + return c; } +wxInputStream& wxInputStream::Read(void *buf, size_t size) +{ + size_t retsize = GetWBack(buf, size); + if (retsize == size) + { + m_lastcount = size; + m_lasterror = wxStream_NOERROR; + return *this; + } + 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) + { + Ungetch(c); + return c; + } + + return 0; +} wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) { - char buf[BUF_TEMP_SIZE]; - size_t bytes_read = BUF_TEMP_SIZE; + char buf[BUF_TEMP_SIZE]; + size_t bytes_read = BUF_TEMP_SIZE; - while (bytes_read == BUF_TEMP_SIZE) { - bytes_read = Read(buf, bytes_read).LastRead(); - bytes_read = stream_out.Write(buf, bytes_read).LastWrite(); - } - return *this; + while (bytes_read == BUF_TEMP_SIZE) + { + bytes_read = Read(buf, bytes_read).LastRead(); + bytes_read = stream_out.Write(buf, bytes_read).LastWrite(); + } + return *this; } off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode) { - return m_i_streambuf->Seek(pos, mode); + /* Should be check and improve, just to remove a slight bug ! + I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */ + if (m_lasterror==wxSTREAM_EOF) + m_lasterror=wxSTREAM_NOERROR; + + /* A call to SeekI() will automatically invalidate any previous call + to Ungetch(), otherwise it would be possible to SeekI() to one + one position, unread some bytes there, SeekI() to another position + and the data would be corrupted. + + GRG: Could add code here to try to navigate within the wback + 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) + { + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + return OnSysSeek(pos, mode); } off_t wxInputStream::TellI() const { - return m_i_streambuf->Tell(); + /* GRG: Changed to make it compatible with the wback buffer */ + off_t pos = OnSysTell(); + + if (pos != wxInvalidOffset) + pos -= (m_wbacksize - m_wbackcur); + + return pos; } // -------------------- // Overloaded operators // -------------------- -wxInputStream& wxInputStream::operator>>(wxString& line) +#if wxUSE_SERIAL +wxInputStream& wxInputStream::operator>>(wxObject *& obj) { - line = ReadLine(); - return *this; + wxObjectInputStream obj_s(*this); + obj = obj_s.LoadObject(); + return *this; } +#endif // wxUSE_SERIAL -wxInputStream& wxInputStream::operator>>(char& c) + +// ---------------------------------------------------------------------------- +// wxOutputStream +// ---------------------------------------------------------------------------- + +wxOutputStream::wxOutputStream() { - c = GetC(); - return *this; } -wxInputStream& wxInputStream::operator>>(signed short& i) +wxOutputStream::~wxOutputStream() { - signed long l; - - *this >> l; - i = (signed short)l; - return *this; } -wxInputStream& wxInputStream::operator>>(signed int& i) +size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer), + size_t WXUNUSED(bufsize)) { - signed long l; - - *this >> l; - i = (signed int)l; - return *this; + return 0; } -wxInputStream& wxInputStream::operator>>(signed long& i) +void wxOutputStream::PutC(char c) { - /* I only implemented a simple integer parser */ - int c; - int sign; - - while (isspace( c = GetC() ) ) - /* Do nothing */ ; + Write(&c, 1); +} - i = 0; - if (! (c == '-' || isdigit(c)) ) { - InputStreamBuffer()->WriteBack(c); +wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) +{ + m_lastcount = OnSysWrite(buffer, size); return *this; - } - - if (c == '-') { - sign = -1; - c = GetC(); - } else if (c == '+') { - sign = 1; - c = GetC(); - } else { - sign = 1; - } - - while (isdigit(c)) { - i = i*10 + (c - (int)'0'); - c = GetC(); - } - - i *= sign; - - return *this; } -wxInputStream& wxInputStream::operator>>(unsigned short& i) +wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) { - unsigned long l; + stream_in.Read(*this); + return *this; +} - *this >> l; - i = (unsigned short)l; - return *this; +off_t wxOutputStream::TellO() const +{ + return OnSysTell(); } -wxInputStream& wxInputStream::operator>>(unsigned int& i) +off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode) { - unsigned long l; + return OnSysSeek(pos, mode); +} - *this >> l; - i = (unsigned int)l; - return *this; +void wxOutputStream::Sync() +{ } -wxInputStream& wxInputStream::operator>>(unsigned long& i) +#if wxUSE_SERIAL +wxOutputStream& wxOutputStream::operator<<(wxObject& obj) { - /* I only implemented a simple integer parser */ - int c; + wxObjectOutputStream obj_s(*this); + obj_s.SaveObject(obj); + return *this; +} +#endif // wxUSE_SERIAL - while (isspace( c = GetC() ) ) - /* Do nothing */ ; +// ---------------------------------------------------------------------------- +// wxCountingOutputStream +// ---------------------------------------------------------------------------- - i = 0; - if (!isdigit(c)) { - InputStreamBuffer()->WriteBack(c); - return *this; - } +wxCountingOutputStream::wxCountingOutputStream () +{ + m_currentPos = 0; +} - while (isdigit(c)) { - i = i*10 + c - '0'; - c = GetC(); - } +size_t wxCountingOutputStream::GetSize() const +{ + return m_lastcount; +} - return *this; +size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), + size_t size) +{ + m_currentPos += size; + if (m_currentPos > m_lastcount) + m_lastcount = m_currentPos; + + return m_currentPos; } -wxInputStream& wxInputStream::operator>>(double& f) +off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode) { - /* I only implemented a simple float parser */ - int c, sign; + switch ( mode ) + { + case wxFromStart: + m_currentPos = pos; + break; - while (isspace( c = GetC() ) ) - /* Do nothing */ ; + case wxFromEnd: + m_currentPos = m_lastcount + pos; + break; - f = 0.0; - if (! (c == '-' || isdigit(c)) ) { - InputStreamBuffer()->WriteBack(c); - return *this; - } - - if (c == '-') { - sign = -1; - c = GetC(); - } else if (c == '+') { - sign = 1; - c = GetC(); - } else { - sign = 1; - } - - while (isdigit(c)) { - f = f*10 + (c - '0'); - c = GetC(); - } - - if (c == '.') { - double f_multiplicator = (double) 0.1; - c = GetC(); - - while (isdigit(c)) { - f += (c-'0')*f_multiplicator; - f_multiplicator /= 10; - c = GetC(); + case wxFromCurrent: + m_currentPos += pos; + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + return wxInvalidOffset; } - } - f *= sign; + if (m_currentPos > m_lastcount) + m_lastcount = m_currentPos; - return *this; + return m_currentPos; } -#if wxUSE_SERIAL -wxInputStream& wxInputStream::operator>>(wxObject *& obj) +off_t wxCountingOutputStream::OnSysTell() const { - wxObjectInputStream obj_s(*this); - obj = obj_s.LoadObject(); - return *this; + return m_currentPos; } -#endif - // ---------------------------------------------------------------------------- -// wxOutputStream +// wxFilterInputStream // ---------------------------------------------------------------------------- -wxOutputStream::wxOutputStream() - : wxStreamBase() + +wxFilterInputStream::wxFilterInputStream() { - m_o_destroybuf = TRUE; - m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); + m_parent_i_stream = NULL; } -wxOutputStream::wxOutputStream(wxStreamBuffer *buffer) - : wxStreamBase() +wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) { - m_o_destroybuf = FALSE; - m_o_streambuf = buffer; + m_parent_i_stream = &stream; } -wxOutputStream::~wxOutputStream() +wxFilterInputStream::~wxFilterInputStream() { - if (m_o_destroybuf) - delete m_o_streambuf; } -wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) +// ---------------------------------------------------------------------------- +// wxFilterOutputStream +// ---------------------------------------------------------------------------- + +wxFilterOutputStream::wxFilterOutputStream() { - m_o_streambuf->Write(buffer, size); - return *this; + m_parent_o_stream = NULL; } -wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) +wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) { - stream_in.Read(*this); - return *this; + m_parent_o_stream = &stream; } -off_t wxOutputStream::TellO() const +wxFilterOutputStream::~wxFilterOutputStream() { - return m_o_streambuf->Tell(); } -off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode) +// ---------------------------------------------------------------------------- +// wxBufferedInputStream +// ---------------------------------------------------------------------------- + +wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, + wxStreamBuffer *buffer) + : wxFilterInputStream(s) { - return m_o_streambuf->Seek(pos, mode); + if ( buffer ) + { + // use the buffer provided by the user + m_i_streambuf = buffer; + } + else // create a default buffer + { + m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); + + m_i_streambuf->SetBufferIO(1024); + } } -void wxOutputStream::Sync() +wxBufferedInputStream::~wxBufferedInputStream() { - m_o_streambuf->FlushBuffer(); + m_parent_i_stream->SeekI(-(off_t)m_i_streambuf->GetBytesLeft(), + wxFromCurrent); + + delete m_i_streambuf; } -void wxOutputStream::WriteLine(const wxString& line) +char wxBufferedInputStream::Peek() { -#ifdef __WXMSW__ - wxString tmp_string = line + _T("\r\n"); -#else -#ifdef __WXMAC__ - wxString tmp_string = line + _T('\r'); -#else - wxString tmp_string = line + _T('\n'); -#endif -#endif - - Write((const wxChar *) tmp_string, tmp_string.Length()*sizeof(wxChar)); + return m_i_streambuf->Peek(); } -wxOutputStream& wxOutputStream::operator<<(const char *string) +wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) { - return Write(string, strlen(string)); + size_t retsize; + + retsize = GetWBack(buf, size); + m_lastcount = retsize; + if ( retsize == size ) + { + m_lasterror = wxStream_NOERROR; + return *this; + } + size -= retsize; + buf = (char *)buf + retsize; + + m_i_streambuf->Read(buf, size); + + return *this; } -wxOutputStream& wxOutputStream::operator<<(wxString& string) +off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode) { -#if wxUSE_UNICODE - const wxWX2MBbuf buf = string.mb_str(); - return *this << buf; -#else - return Write(string, string.Len()); -#endif + return m_i_streambuf->Seek(pos, mode); } -wxOutputStream& wxOutputStream::operator<<(char c) +off_t wxBufferedInputStream::TellI() const { - return Write(&c, 1); + return m_i_streambuf->Tell(); } -wxOutputStream& wxOutputStream::operator<<(signed short i) +size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize) { - signed long l = (signed long)i; - return *this << l; + return m_parent_i_stream->Read(buffer, bufsize).LastRead(); } -wxOutputStream& wxOutputStream::operator<<(signed int i) +off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode) { - signed long l = (signed long)i; - return *this << l; + return m_parent_i_stream->SeekI(seek, mode); } -wxOutputStream& wxOutputStream::operator<<(signed long i) +off_t wxBufferedInputStream::OnSysTell() const { - wxString strlong; - strlong.Printf(_T("%ld"), i); - return *this << strlong; + return m_parent_i_stream->TellI(); } -wxOutputStream& wxOutputStream::operator<<(unsigned short i) +void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer) { - unsigned long l = (unsigned long)i; - return *this << l; + wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") ); + + delete m_i_streambuf; + m_i_streambuf = buffer; } -wxOutputStream& wxOutputStream::operator<<(unsigned int i) +// ---------------------------------------------------------------------------- +// wxBufferedOutputStream +// ---------------------------------------------------------------------------- + +wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s, + wxStreamBuffer *buffer) + : wxFilterOutputStream(s) { - unsigned long l = (unsigned long)i; - return *this << l; + if ( buffer ) + { + m_o_streambuf = buffer; + } + else // create a default one + { + m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); + + m_o_streambuf->SetBufferIO(1024); + } } -wxOutputStream& wxOutputStream::operator<<(unsigned long i) +wxBufferedOutputStream::~wxBufferedOutputStream() { - wxString strlong; - strlong.Printf(_T("%lu"), i); - return *this << strlong; + Sync(); + delete m_o_streambuf; } -wxOutputStream& wxOutputStream::operator<<(double f) +wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size) { - wxString strfloat; + m_lastcount = 0; + m_o_streambuf->Write(buffer, size); + return *this; +} - strfloat.Printf(_T("%f"), f); - return *this << strfloat; +off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode) +{ + Sync(); + return m_o_streambuf->Seek(pos, mode); } -#if wxUSE_SERIAL -wxOutputStream& wxOutputStream::operator<<(wxObject& obj) +off_t wxBufferedOutputStream::TellO() const { - wxObjectOutputStream obj_s(*this); - obj_s.SaveObject(obj); - return *this; + return m_o_streambuf->Tell(); } -#endif -// ---------------------------------------------------------------------------- -// wxFilterInputStream -// ---------------------------------------------------------------------------- -wxFilterInputStream::wxFilterInputStream() - : wxInputStream(NULL) +void wxBufferedOutputStream::Sync() { - // WARNING streambuf set to NULL ! + m_o_streambuf->FlushBuffer(); + m_parent_o_stream->Sync(); } -wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) - : wxInputStream(stream.InputStreamBuffer()) +size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize) { - m_parent_i_stream = &stream; + return m_parent_o_stream->Write(buffer, bufsize).LastWrite(); } -wxFilterInputStream::~wxFilterInputStream() +off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode) { + return m_parent_o_stream->SeekO(seek, mode); } -// ---------------------------------------------------------------------------- -// wxFilterOutputStream -// ---------------------------------------------------------------------------- -wxFilterOutputStream::wxFilterOutputStream() - : wxOutputStream(NULL) +off_t wxBufferedOutputStream::OnSysTell() const { + return m_parent_o_stream->TellO(); } -wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) - : wxOutputStream(stream.OutputStreamBuffer()) +size_t wxBufferedOutputStream::GetSize() const { - m_parent_o_stream = &stream; + return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition(); } -wxFilterOutputStream::~wxFilterOutputStream() +void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer) { + wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") ); + + delete m_o_streambuf; + m_o_streambuf = buffer; } // ----------------------------------------------------------------------------