X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b23bc769d3d1943ca2b02ca90701d86b00880af9..af58844636f51ca9c9350c66de3baf427d3e8646:/src/common/stream.cpp diff --git a/src/common/stream.cpp b/src/common/stream.cpp index c612f4835b..357499b047 100644 --- a/src/common/stream.cpp +++ b/src/common/stream.cpp @@ -75,24 +75,24 @@ void wxStreamBuffer::Init() 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) @@ -916,13 +916,48 @@ wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) { // RR: This code is duplicated in wxBufferedInputStream. This is // not really a good design, but buffered stream are different - // from all other in that they handle two stream-related objects, + // from all others in that they handle two stream-related objects: // the stream buffer and parent stream. // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek if (m_lasterror==wxSTREAM_EOF) m_lasterror=wxSTREAM_NO_ERROR; + // avoid unnecessary seek operations (optimization) + wxFileOffset currentPos = TellI(), size = GetLength(); + if ((mode == wxFromStart && currentPos == pos) || + (mode == wxFromCurrent && pos == 0) || + (mode == wxFromEnd && size != wxInvalidOffset && currentPos == size-pos)) + return currentPos; + + if (!IsSeekable() && mode == wxFromCurrent && pos > 0) + { + // rather than seeking, we can just read data and discard it; + // this allows to forward-seek also non-seekable streams! + char buf[BUF_TEMP_SIZE]; + size_t bytes_read; + + // read chunks of BUF_TEMP_SIZE bytes until we reach the new position + for ( ; pos >= BUF_TEMP_SIZE; pos -= bytes_read) + { + bytes_read = Read(buf, WXSIZEOF(buf)).LastRead(); + if ( m_lasterror != wxSTREAM_NO_ERROR ) + return wxInvalidOffset; + + wxASSERT(bytes_read == WXSIZEOF(buf)); + } + + // read the last 'pos' bytes + bytes_read = Read(buf, (size_t)pos).LastRead(); + if ( m_lasterror != wxSTREAM_NO_ERROR ) + return wxInvalidOffset; + + wxASSERT(bytes_read == (size_t)pos); + + // we should now have seeked to the right position... + return TellI(); + } + /* RR: A call to SeekI() will automatically invalidate any previous call to Ungetch(), otherwise it would be possible to SeekI() to one position, unread some bytes there, SeekI() to another position @@ -1204,21 +1239,33 @@ void wxFilterClassFactory::Remove() // wxBufferedInputStream // ---------------------------------------------------------------------------- -wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, +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 +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(s) + : wxFilterInputStream(stream) { - 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 = CreateBufferIfNeeded(*this, buffer); +} - m_i_streambuf->SetBufferIO(1024); - } +wxBufferedInputStream::wxBufferedInputStream(wxInputStream& stream, + size_t bufsize) + : wxFilterInputStream(stream) +{ + m_i_streambuf = CreateBufferIfNeeded(*this, NULL, bufsize); } wxBufferedInputStream::~wxBufferedInputStream() @@ -1248,12 +1295,15 @@ wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) 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; } @@ -1317,20 +1367,18 @@ void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *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()