]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/stream.cpp
implemented fallback for AlphaBlend() for the systems not supporting it
[wxWidgets.git] / src / common / stream.cpp
index 189916814b5336e8b7ab7868e7a6dad3b7f68dd9..2770a5df20a5cb9946dc1d641f1a57269cafa3a5 100644 (file)
@@ -7,7 +7,7 @@
 // Created:     11/07/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Guilhem Lavaux
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // ============================================================================
 #include <ctype.h>
 #include "wx/stream.h"
 #include "wx/datstrm.h"
-#include "wx/objstrm.h"
+#include "wx/textfile.h"
+#include "wx/log.h"
 
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
 
 // the temporary buffer size used when copying from stream to stream
-#define BUF_TEMP_SIZE 10000
+#define BUF_TEMP_SIZE 4096
 
 // ============================================================================
 // implementation
@@ -57,7 +58,7 @@
 
 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;
 }
 
@@ -68,8 +69,8 @@ void wxStreamBuffer::InitBuffer()
     m_buffer_pos = NULL;
     m_buffer_size = 0;
 
-    // there is nothing to destroy anyhow
-    m_destroybuf = FALSE;
+    // if we are going to allocate the buffer, we should free it later as well
+    m_destroybuf = TRUE;
 }
 
 void wxStreamBuffer::Init()
@@ -79,33 +80,31 @@ void wxStreamBuffer::Init()
     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();
 
-    m_stream = new wxStreamBase;
+    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;
@@ -117,7 +116,6 @@ wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
     m_stream = buffer.m_stream;
     m_mode = buffer.m_mode;
     m_destroybuf = FALSE;
-    m_destroystream = FALSE;
 }
 
 void wxStreamBuffer::FreeBuffer()
@@ -129,9 +127,6 @@ void wxStreamBuffer::FreeBuffer()
 wxStreamBuffer::~wxStreamBuffer()
 {
     FreeBuffer();
-
-    if ( m_destroystream )
-        delete m_stream;
 }
 
 wxInputStream *wxStreamBuffer::GetInputStream() const
@@ -165,7 +160,7 @@ void wxStreamBuffer::SetBufferIO(void *start,
     m_buffer_size = len;
 
     // if we own it, we free it
-    m_destroybuf = !takeOwnership;
+    m_destroybuf = takeOwnership;
 
     ResetBuffer();
 }
@@ -187,14 +182,15 @@ void wxStreamBuffer::SetBufferIO(size_t bufsize)
 
 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)
@@ -202,7 +198,9 @@ bool wxStreamBuffer::FillBuffer()
 {
     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 )
@@ -263,6 +261,7 @@ void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
 {
     size_t left = GetBytesLeft();
+
     if ( size > left )
     {
         if ( m_fixed )
@@ -307,7 +306,7 @@ void wxStreamBuffer::PutChar(char c)
     // 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
     {
@@ -315,11 +314,11 @@ void wxStreamBuffer::PutChar(char c)
         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;
         }
     }
@@ -332,12 +331,12 @@ char wxStreamBuffer::Peek()
 
     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;
@@ -352,18 +351,18 @@ char wxStreamBuffer::GetChar()
     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;
         }
     }
@@ -373,16 +372,18 @@ char wxStreamBuffer::GetChar()
 
 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
     {
@@ -402,7 +403,7 @@ size_t wxStreamBuffer::Read(void *buffer, size_t size)
 
                 if ( !FillBuffer() )
                 {
-                    SetError(wxStream_EOF);
+                    SetError(wxSTREAM_EOF);
                     break;
                 }
             }
@@ -413,10 +414,13 @@ size_t wxStreamBuffer::Read(void *buffer, size_t size)
             }
         }
 
-        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()"
@@ -444,17 +448,22 @@ size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
 
 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
 {
-    wxOutputStream *outStream = GetOutputStream();
-
-    wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
+    if (m_stream)
+    {
+        // lasterror is reset before all new IO calls
+        m_stream->Reset();
+    }
 
-    // lasterror is reset before all new IO calls
-    m_stream->m_lasterror = wxStream_NOERROR;
+    size_t ret = 0;
 
     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
     {
@@ -472,6 +481,7 @@ size_t wxStreamBuffer::Write(const void *buffer, size_t size)
             //
             // 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);
@@ -480,7 +490,7 @@ size_t wxStreamBuffer::Write(const void *buffer, size_t size)
 
                 if ( !FlushBuffer() )
                 {
-                    SetError(wxStream_WRITE_ERR);
+                    SetError(wxSTREAM_WRITE_ERROR);
 
                     break;
                 }
@@ -494,10 +504,16 @@ size_t wxStreamBuffer::Write(const void *buffer, size_t size)
             }
         }
 
-        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)
@@ -605,9 +621,19 @@ off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
 
 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();
 
@@ -623,7 +649,7 @@ off_t wxStreamBuffer::Tell() const
 
 wxStreamBase::wxStreamBase()
 {
-    m_lasterror = wxStream_NOERROR;
+    m_lasterror = wxSTREAM_NO_ERROR;
     m_lastcount = 0;
 }
 
@@ -657,26 +683,19 @@ wxInputStream::~wxInputStream()
     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);
-    if ( 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)
@@ -690,14 +709,14 @@ char *wxInputStream::AllocSpaceWBack(size_t needed_size)
     if (!temp_b)
         return NULL;
 
-    /* copy previous data (and free old buffer) if needed */
+    // 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 */
+    // done
     m_wback = temp_b;
     m_wbackcur = 0;
     m_wbacksize = needed_size + toget;
@@ -705,78 +724,110 @@ 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)
 {
-    size_t toget = m_wbacksize-m_wbackcur;
-
     if (!m_wback)
         return 0;
 
-    if (bsize < toget)
-       toget = bsize;
+    // how many bytes do we have in the buffer?
+    size_t toget = m_wbacksize - m_wbackcur;
+
+    if ( size < toget )
+    {
+        // we won't read everything
+        toget = size;
+    }
 
-    memcpy(buf, (m_wback+m_wbackcur), toget);
+    // copy the data from the cache
+    memcpy(buf, m_wback + m_wbackcur, toget);
 
     m_wbackcur += toget;
-    if (m_wbackcur == m_wbacksize)
+    if ( m_wbackcur == m_wbacksize )
     {
+        // TODO: should we really free it here all the time? maybe keep it?
         free(m_wback);
         m_wback = NULL;
         m_wbacksize = 0;
         m_wbackcur = 0;
     }
 
+    // return the number of bytes copied
     return 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;
@@ -788,35 +839,45 @@ char wxInputStream::Peek()
 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;
 }
 
 off_t wxInputStream::SeekI(off_t pos, wxSeekMode 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 ? */
+    // 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,
+    // 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_NOERROR;
+        m_lasterror=wxSTREAM_NO_ERROR;
 
-    /* A call to SeekI() will automatically invalidate any previous call
-       to Ungetch(), otherwise it would be possible to SeekI() to one
+    /* 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
        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...
-     */
+       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;
@@ -828,7 +889,6 @@ off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
 
 off_t wxInputStream::TellI() const
 {
-    /* GRG: Changed to make it compatible with the wback buffer */
     off_t pos = OnSysTell();
 
     if (pos != wxInvalidOffset)
@@ -837,19 +897,6 @@ off_t wxInputStream::TellI() const
     return pos;
 }
 
-// --------------------
-// Overloaded operators
-// --------------------
-
-#if wxUSE_SERIAL
-wxInputStream& wxInputStream::operator>>(wxObject *& obj)
-{
-    wxObjectInputStream obj_s(*this);
-    obj = obj_s.LoadObject();
-    return *this;
-}
-#endif // wxUSE_SERIAL
-
 
 // ----------------------------------------------------------------------------
 // wxOutputStream
@@ -871,7 +918,7 @@ size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
 
 void wxOutputStream::PutC(char c)
 {
-    Write(&c, 1);
+    Write(&c, sizeof(c));
 }
 
 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
@@ -900,14 +947,6 @@ void wxOutputStream::Sync()
 {
 }
 
-#if wxUSE_SERIAL
-wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
-{
-    wxObjectOutputStream obj_s(*this);
-    obj_s.SaveObject(obj);
-    return *this;
-}
-#endif // wxUSE_SERIAL
 
 // ----------------------------------------------------------------------------
 // wxCountingOutputStream
@@ -1037,31 +1076,58 @@ char wxBufferedInputStream::Peek()
 
 wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
 {
-    size_t retsize;
+    // reset the error flag
+    Reset();
 
-    retsize = GetWBack(buf, size);
-    m_lastcount = retsize;
-    if ( retsize == size )
+    // first read from the already cached data
+    m_lastcount = GetWBack(buf, size);
+
+    // do we have to read anything more?
+    if ( m_lastcount < size )
     {
-        m_lasterror = wxStream_NOERROR;
-        return *this;
-    }
-    size -= retsize;
-    buf = (char *)buf + retsize;
+        size -= m_lastcount;
+        buf = (char *)buf + m_lastcount;
 
-    m_i_streambuf->Read(buf, size);
+        // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
+        // so save it
+        size_t countOld = m_lastcount;
+
+        m_i_streambuf->Read(buf, size);
+
+        m_lastcount += countOld;
+    }
 
     return *this;
 }
 
 off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
 {
+    // RR: Look at wxInputStream for comments.
+
+    if (m_lasterror==wxSTREAM_EOF)
+        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);
 }
 
 off_t wxBufferedInputStream::TellI() const
 {
-    return m_i_streambuf->Tell();
+    off_t pos = m_i_streambuf->Tell();
+
+    if (pos != wxInvalidOffset)
+        pos -= (m_wbacksize - m_wbackcur);
+
+    return pos;
 }
 
 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
@@ -1171,15 +1237,9 @@ void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
 
 wxOutputStream& wxEndL(wxOutputStream& stream)
 {
-#ifdef __MSW__
-  return stream.Write("\r\n", 2);
-#else
-#ifdef __WXMAC__
-  return stream.Write("\r", 1);
-#else
-  return stream.Write("\n", 1);
-#endif
-#endif
+    static const wxChar *eol = wxTextFile::GetEOL();
+
+    return stream.Write(eol, wxStrlen(eol));
 }
 
 #endif